version 2.0.0-b1

This commit is contained in:
Gerhard Rieger 2008-02-17 14:59:16 +01:00
parent b819572f5e
commit db717446a4
96 changed files with 6419 additions and 2363 deletions

28
CHANGES
View file

@ -1,4 +1,32 @@
####################### V 2.0.0-b1:
new features:
address chains consisting of inter and endpoint addresses, linked with
'|' (pipe character)
reverting inter addresses
dual type inter addresses
changed form of dual addresses from in!!out to out%in
address overloading per parameter number, inter/endpoint type, and
supported transfer directions
derived new inter addresses OPENSSL-CLIENT, OPENSSL-SERVER,
PROXY-CLIENT, SOCKS4-CLIENT, SOCKS4A-CLIENT from related old addresses
new inter address SOCKS5-CLIENT
new inter address NOP
new inter address TEST, TESTUNI, TESTREV
new form of PTY address with symlink paramater
new form of FD address with output/input fd numbers
####################### V 1.6.0.0: ####################### V 1.6.0.0:
new features: new features:

View file

@ -87,7 +87,7 @@ $ socat -u -,cr -
// save piped data similar to 'tee': // save piped data similar to 'tee':
// copies stdin to stdout, but writes everything to the file too // copies stdin to stdout, but writes everything to the file too
$ socat -,echo=0 open:/tmp/myfile,create,trunc,ignoreeof!!/tmp/myfile $ socat - OPEN:/tmp/myfile,create,trunc%open:/tmp/myfile,ignoreeof
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// intrusion testing // intrusion testing
@ -113,23 +113,23 @@ $ socat -,echo=0 open:/tmp/myfile,create,trunc,ignoreeof!!/tmp/myfile
// forms of stdin with stdout, all equivalent // forms of stdin with stdout, all equivalent
$ socat echo - $ socat echo -
$ socat echo STDIO $ socat echo STDIO
$ socat echo STDIN!!STDOUT $ socat echo STDOUT%STDIN
$ socat echo STDIO!!STDIO $ socat echo STDIO%STDIO
$ socat echo -!!- $ socat echo -%-
$ socat echo FD:0!!FD:1 $ socat echo FD:1%FD:0
$ socat echo 0!!1 $ socat echo 1%0
$ socat echo /dev/stdin!!/dev/stdout // if your OS provides these $ socat echo /dev/stdout%/dev/stdin // if your OS provides these
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// some echo address examples // some echo address examples
$ socat - PIPE $ socat - PIPE
$ socat - PIPE:/tmp/pipi // other version of echo $ socat - PIPE:/tmp/pipi // other version of echo
$ socat - PIPE:/tmp/pipi,nonblock!!/tmp/pipi // other version of echo $ socat - PIPE:/tmp/pipi%/tmp/pipi // other version of echo
$ socat - EXEC:/bin/cat // another echo $ socat - EXEC:/bin/cat // another echo
$ socat - SYSTEM:/bin/cat // another echo $ socat - SYSTEM:/bin/cat // another echo
$ socat - TCP:loopback:7 // if inetd echo/TCP service activated $ socat - TCP:loopback:7 // if inetd echo/TCP service activated
$ socat - UDP:loopback:7 // if inetd echo/UDP service activated $ socat - UDP:loopback:7 // if inetd echo/UDP service activated
$ socat - /tmp/hugo,trunc,ignoreeof!!/tmp/hugo // with delay $ socat - /tmp/hugo,trunc%/tmp/hugo,ignoreeof // with delay
$ socat - UDP:loopback:2000,bind=:2000 // self "connection" $ socat - UDP:loopback:2000,bind=:2000 // self "connection"
$ socat - TCP:loopback:2000,bind=:2000 // Linux bug? $ socat - TCP:loopback:2000,bind=:2000 // Linux bug?
# socat - IP:loopback:222 // raw protocol, self "connected" (attention, # socat - IP:loopback:222 // raw protocol, self "connected" (attention,
@ -151,7 +151,7 @@ $ socat -u - CREATE:/tmp/outfile1,group=floppy,perm=0640
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// file handling // file handling
$ socat - FILE:/tmp/outfile1,ignoreeof!!FILE:/tmp/outfile1,append // prints outfile1, then echoes input and protocols into file (appends to old data) $ socat - FILE:/tmp/outfile1,append%FILE:/tmp/outfile1,ignoreeof // prints outfile1, then echoes input and protocols into file (appends to old data)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// unix socket handling // unix socket handling

8
FAQ
View file

@ -57,14 +57,6 @@ But the following OS differences result in errors on non Linux systems:
$PATH, and "openssl s_server ..." needs enough entropy to generate a key. $PATH, and "openssl s_server ..." needs enough entropy to generate a key.
Q: When I specify a dual address (two partial addresses linked with "!!") on
the command line, I get some message "event not found", and my shell history
has the line truncated. Not even protecting the '!'s with '\' helps.
A: '!' is appearently used by your shell as history expansion character. Say
"set +H" and add this line to your (bash) profile.
Q: On Solaris, socat was built successfully, but when started, it gets killed Q: On Solaris, socat was built successfully, but when started, it gets killed
with something like "ld.so.1: ./socat: fatal: libreadline.so.4: open failed: no with something like "ld.so.1: ./socat: fatal: libreadline.so.4: open failed: no
such file or directory" such file or directory"

View file

@ -37,18 +37,19 @@ INSTALL = @INSTALL@
#0 CFLAGS = @CFLAGS@ $(CCOPTS) $(DEFS) $(INCLS) #0 CFLAGS = @CFLAGS@ $(CCOPTS) $(DEFS) $(INCLS)
CFLAGS = @CFLAGS@ $(CCOPTS) $(DEFS) $(CPPFLAGS) CFLAGS = @CFLAGS@ $(CCOPTS) $(DEFS) $(CPPFLAGS)
CLIBS = $(LIBS) CLIBS = $(LIBS) -lpthread
#CLIBS = $(LIBS) -lm -lefence #CLIBS = $(LIBS) -lm -lefence
XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \ XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \
xiosignal.c xiosigchld.c xioread.c xiowrite.c \ xiosignal.c xiosigchld.c xioread.c xiowrite.c xiotransfer.c xioengine.c \
xiolayer.c xioshutdown.c xioclose.c xioexit.c \ xiolayer.c xioshutdown.c xioclose.c xioexit.c xiosocketpair.c \
xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \ xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \
xio-gopen.c xio-creat.c xio-file.c xio-named.c \ xio-gopen.c xio-creat.c xio-file.c xio-named.c \
xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-proxy.c xio-udp.c \ xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-socks5.c xio-proxy.c xio-udp.c \
xio-rawip.c \ xio-rawip.c \
xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \ xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \
xio-pty.c xio-openssl.c \ xio-pty.c xio-openssl.c \
xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c xio-tun.c xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c xio-tun.c \
xio-nop.c xio-test.c
XIOOBJS = $(XIOSRCS:.c=.o) XIOOBJS = $(XIOSRCS:.c=.o)
UTLSRCS = error.c dalan.c procan.c hostan.c fdname.c sysutils.c utils.c nestlex.c @FILAN@ @SYCLS@ @SSLCLS@ UTLSRCS = error.c dalan.c procan.c hostan.c fdname.c sysutils.c utils.c nestlex.c @FILAN@ @SYCLS@ @SSLCLS@
UTLOBJS = $(UTLSRCS:.c=.o) UTLOBJS = $(UTLSRCS:.c=.o)
@ -61,24 +62,24 @@ HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.
xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \ xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \
xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \ xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \
xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \ xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \
xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \ xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-socks5.h xio-proxy.h xio-progcall.h xio-exec.h \
xio-system.h xio-termios.h xio-readline.h \ xio-system.h xio-termios.h xio-readline.h \
xio-pty.h xio-openssl.h \ xio-pty.h xio-openssl.h \
xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h xio-tun.h xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h xio-tun.h \
xiosigchld.h xiostatic.h xio-nop.h xio-test.h
DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT doc/socat.1 doc/socat.html FAQ BUGREPORTS COPYING COPYING.OpenSSL doc/dest-unreach.css doc/socat-openssltunnel.html doc/socat-multicast.html doc/socat-tun.html
DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT doc/socat.1 doc/socat.html doc/xio.help FAQ BUGREPORTS COPYING COPYING.OpenSSL doc/dest-unreach.css doc/socat-openssltunnel.html doc/socat-multicast.html doc/socat-tun.html
SHFILES = daemon.sh mail.sh ftp.sh readline.sh SHFILES = daemon.sh mail.sh ftp.sh readline.sh
TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \ TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \
proxy.sh socks4a-echo.sh testcert.conf proxy.sh socks4a-echo.sh testcert.conf
OSFILES = Config/Makefile.Linux-2-6-16 Config/config.Linux-2-6-16.h \ #OSFILES = Config/Makefile.Linux-2-6-16 Config/config.Linux-2-6-16.h \
Config/Makefile.AIX-5-1 Config/config.AIX-5-1.h \ # Config/Makefile.AIX-5-1 Config/config.AIX-5-1.h \
Config/Makefile.SunOS-5-8 Config/config.SunOS-5-8.h \ # Config/Makefile.SunOS-5-8 Config/config.SunOS-5-8.h \
Config/Makefile.HP-UX-B-11-11 Config/config.HP-UX-B-11-11.h \ # Config/Makefile.HP-UX-B-11-11 Config/config.HP-UX-B-11-11.h \
Config/Makefile.FreeBSD-6-1 Config/config.FreeBSD-6-1.h \ # Config/Makefile.FreeBSD-6-1 Config/config.FreeBSD-6-1.h \
Config/Makefile.NetBSD-2-0-2 Config/config.NetBSD-2-0-2.h \ # Config/Makefile.NetBSD-2-0-2 Config/config.NetBSD-2-0-2.h \
Config/Makefile.OpenBSD-3-8 Config/config.OpenBSD-3-8.h \ # Config/Makefile.OpenBSD-3-8 Config/config.OpenBSD-3-8.h \
Config/Makefile.Tru64-5-1B Config/config.Tru64-5-1B.h # Config/Makefile.Tru64-5-1B Config/config.Tru64-5-1B.h
all: progs all: progs
@ -133,7 +134,7 @@ socat.tar.bz2: socat.tar
VERSION = `sed 's/"//g' VERSION` VERSION = `sed 's/"//g' VERSION`
TARDIR = socat-$(VERSION) TARDIR = socat-$(VERSION)
socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(OSFILES) $(TESTFILES) socat.spec socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(OSFILES) $(TESTFILES)
if [ ! -d $(TARDIR) ]; then mkdir $(TARDIR); fi if [ ! -d $(TARDIR) ]; then mkdir $(TARDIR); fi
tar cf - $+ |(cd $(TARDIR); tar xf -) tar cf - $+ |(cd $(TARDIR); tar xf -)
tar cvf socat.tar $(TARDIR) tar cvf socat.tar $(TARDIR)

View file

@ -1 +1 @@
"1.6.0.0" "2.0.0-b1"

View file

@ -1,5 +1,5 @@
/* $Id: compat.h,v 1.32 2006/06/19 20:28:52 gerhard Exp $ */ /* $Id: compat.h,v 1.32 2006/06/19 20:28:52 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __compat_h_included #ifndef __compat_h_included
@ -587,6 +587,8 @@
# endif # endif
#endif #endif
#define F_thread "%lu"
/* Cygwin 1.3.22 has the prototypes, but not the type... */ /* Cygwin 1.3.22 has the prototypes, but not the type... */
#ifndef HAVE_TYPE_STAT64 #ifndef HAVE_TYPE_STAT64
# undef HAVE_STAT64 # undef HAVE_STAT64

View file

@ -444,6 +444,8 @@
#undef HAVE_PROC_DIR_FD #undef HAVE_PROC_DIR_FD
#undef WITH_HELP #undef WITH_HELP
#undef WITH_NOP
#undef WITH_TEST
#undef WITH_STDIO #undef WITH_STDIO
#undef WITH_FDNUM #undef WITH_FDNUM
#undef WITH_FILE #undef WITH_FILE
@ -461,6 +463,8 @@
#undef WITH_LISTEN #undef WITH_LISTEN
#undef WITH_SOCKS4 #undef WITH_SOCKS4
#undef WITH_SOCKS4A #undef WITH_SOCKS4A
#define WITH_SOCKS5 1
#define WITH_SOCKS4_SERVER 1
#undef WITH_PROXY #undef WITH_PROXY
#undef WITH_EXEC #undef WITH_EXEC
#undef WITH_SYSTEM #undef WITH_SYSTEM

View file

@ -90,6 +90,22 @@ AC_ARG_ENABLE(help, [ --disable-help disable help],
esac], esac],
[AC_DEFINE(WITH_HELP) AC_MSG_RESULT(yes)]) [AC_DEFINE(WITH_HELP) AC_MSG_RESULT(yes)])
AC_MSG_CHECKING(whether to include nop address support)
AC_ARG_ENABLE(nop, [ --disable-nop disable nop support],
[case "$enableval" in
no) AC_MSG_RESULT(no);;
*) AC_DEFINE(WITH_NOP) AC_MSG_RESULT(yes);;
esac],
[AC_DEFINE(WITH_NOP) AC_MSG_RESULT(yes)])
AC_MSG_CHECKING(whether to include test address support)
AC_ARG_ENABLE(test, [ --disable-test disable test support],
[case "$enableval" in
no) AC_MSG_RESULT(no);;
*) AC_DEFINE(WITH_TEST) AC_MSG_RESULT(yes);;
esac],
[AC_DEFINE(WITH_TEST) AC_MSG_RESULT(yes)])
AC_MSG_CHECKING(whether to include STDIO support) AC_MSG_CHECKING(whether to include STDIO support)
AC_ARG_ENABLE(stdio, [ --disable-stdio disable STDIO support], AC_ARG_ENABLE(stdio, [ --disable-stdio disable STDIO support],
[case "$enableval" in [case "$enableval" in

View file

@ -1,11 +1,17 @@
.TH "socat" "1" "March 2007" "socat" "" .TH "socat" "1" "July 2006" "socat" ""
.PP .PP
.PP .PP
.SH "NAME" .SH "NAME"
socat \- Multipurpose relay (SOcket CAT) socat \- Multipurpose relay (SOcket CAT)
.PP .PP
.SH "SYNOPSIS" .SH "SYNOPSIS"
\f(CWsocat [options] <address> <address>\fP \f(CWsocat [options] <right-address>\fP
.br
\f(CWsocat [options] <left-address> <right-address>\fP
.br
\f(CWsocat [options] <left-address> <right-address> \&.\&.\fP
.br
\f(CWsocat [options] <left-addresses> \&.\&. -- <right-address> \&.\&.\fP
.br .br
\f(CWsocat -V\fP \f(CWsocat -V\fP
.br .br
@ -142,7 +148,7 @@ nothing has happened for <timeout> [timeval] seconds
Useful with protocols like UDP that cannot transfer EOF\&. Useful with protocols like UDP that cannot transfer EOF\&.
.IP "\fB\f(CW-u\fP\fP" .IP "\fB\f(CW-u\fP\fP"
Uses unidirectional mode\&. The first address is only used for reading, and the Uses unidirectional mode\&. The first address is only used for reading, and the
second address is only used for writing (example)\&. second address is only used for writing\&.
.IP "\fB\f(CW-U\fP\fP" .IP "\fB\f(CW-U\fP\fP"
Uses unidirectional mode in reverse direction\&. The first address is only Uses unidirectional mode in reverse direction\&. The first address is only
used for writing, and the second address is only used for reading\&. used for writing, and the second address is only used for reading\&.
@ -252,7 +258,7 @@ path, the \f(CWexecvp()\fP semantics for finding the program via
\f(CW$PATH\fP \f(CW$PATH\fP
apply\&. After successful program start, \fBsocat\fP writes data to stdin of the apply\&. After successful program start, \fBsocat\fP writes data to stdin of the
process and reads from its stdout using a UNIX domain socket generated by process and reads from its stdout using a UNIX domain socket generated by
\f(CWsocketpair()\fP per default\&. (example) \f(CWsocketpair()\fP per default\&.
.br .br
Option groups: FD,SOCKET,EXEC,FORK,TERMIOS Option groups: FD,SOCKET,EXEC,FORK,TERMIOS
.br .br
@ -294,7 +300,7 @@ In case of a UNIX domain socket, \fBsocat\fP connects; if connecting fails,
If the entry is not a socket, \fBsocat\fP opens it applying the \f(CWO_APPEND\fP If the entry is not a socket, \fBsocat\fP opens it applying the \f(CWO_APPEND\fP
flag\&. flag\&.
If it does not exist, it is opened with flag If it does not exist, it is opened with flag
\f(CWO_CREAT\fP as a regular file (example)\&. \f(CWO_CREAT\fP as a regular file\&.
.br .br
Option groups: FD,REG,SOCKET,NAMED,OPEN Option groups: FD,REG,SOCKET,NAMED,OPEN
.br .br
@ -315,7 +321,9 @@ Option groups: FD,SOCKET,IP4,IP6
.br .br
Useful options: Useful options:
pf, pf,
ttl ttl,
broadcast
.br
See also: See also:
IP4-SENDTO, IP4-SENDTO,
IP6-SENDTO, IP6-SENDTO,
@ -334,52 +342,6 @@ Like IP-SENDTO, but always uses IPv6\&.
Option groups: FD,SOCKET,IP6 Option groups: FD,SOCKET,IP6
.br .br
.IP .IP
.IP "\fB\f(CWIP-DATAGRAM:<address>:<protocol>\fP\fP"
Sends outgoing data to the specified address which may in particular be a
broadcast or multicast address\&. Packets arriving on the local socket are
checked if their source addresses match
eventual RANGE or TCPWRAP
options\&. This address type can for example be used for implementing
symmetric or asymmetric broadcast or multicast communications\&.
.br
Option groups: FD, SOCKET,
IP4, IP6, RANGE
.br
Useful options:
range,
tcpwrap,
broadcast,
ip-multicast-loop,
ip-multicast-ttl,
ip-multicast-if,
ip-add-membership,
ttl,
tos,
bind,
pf
.br
See also:
IP4-DATAGRAM,
IP6-DATAGRAM,
IP-SENDTO,
IP-RECVFROM,
IP-RECV,
UDP-DATAGRAM
.IP "\fB\f(CWIP4-DATAGRAM:<host>:<protocol>\fP\fP"
Like IP-DATAGRAM, but always uses IPv4\&.
(example)
.br
Option groups: FD, SOCKET,
IP4, RANGE
.br
.IP "\fB\f(CWIP6-DATAGRAM:<host>:<protocol>\fP\fP"
Like IP-DATAGRAM, but always uses IPv6\&. Please
note that IPv6 does not know broadcasts\&.
.br
Option groups: FD, SOCKET,
IP6, RANGE
.br
.IP
.IP "\fB\f(CWIP-RECVFROM:<protocol>\fP\fP" .IP "\fB\f(CWIP-RECVFROM:<protocol>\fP\fP"
Opens a raw IP socket of <protocol>\&. Depending on option pf, IP procotol version Opens a raw IP socket of <protocol>\&. Depending on option pf, IP procotol version
4 or 6 is used\&. It receives one packet from an unspecified peer and may send one or more answer packets to that peer\&. 4 or 6 is used\&. It receives one packet from an unspecified peer and may send one or more answer packets to that peer\&.
@ -449,8 +411,7 @@ Option groups: FD,SOCKET,IP6,RANGE
.br .br
.IP .IP
.IP "\fB\f(CWOPEN:<filename>\fP\fP" .IP "\fB\f(CWOPEN:<filename>\fP\fP"
Opens <filename> using the \f(CWopen()\fP system call Opens <filename> using the \f(CWopen()\fP system call\&.
(example)\&.
This operation fails on UNIX domain sockets\&. This operation fails on UNIX domain sockets\&.
.br .br
Note: This address type is rarly useful in bidirectional mode\&. Note: This address type is rarly useful in bidirectional mode\&.
@ -510,9 +471,11 @@ connection is accepted, this address behaves as SSL server\&.
.br .br
Note: You probably want to use the certificate option with this address\&. Note: You probably want to use the certificate option with this address\&.
.br .br
NOTE: The client certificate is only checked for validity against NOTE: Without verify option, the client certificate is
cafile or capath, not checked\&. Even with verify option, the client
but not for match with the client\'s name or its IP address! certificate is only checked for validity against cafile
or capath, but not for match with the client\'s name or
its IP address!
.br .br
Option groups: FD,SOCKET,IP4,IP6,TCP,LISTEN,OPENSSL,CHILD,RANGE,RETRY Option groups: FD,SOCKET,IP4,IP6,TCP,LISTEN,OPENSSL,CHILD,RANGE,RETRY
.br .br
@ -596,11 +559,12 @@ retry
.br .br
See also: SOCKS, TCP See also: SOCKS, TCP
.IP "\fB\f(CWPTY\fP\fP" .IP "\fB\f(CWPTY\fP\fP"
.IP "\fB\f(CWPTY:<symlink>\fP\fP"
Generates a pseudo terminal (pty) and uses its master side\&. Another process Generates a pseudo terminal (pty) and uses its master side\&. Another process
may open the pty\'s slave side using it like a serial line or terminal\&. may open the pty\'s slave side using it like a serial line or terminal\&. If
(example)\&. If
both the ptmx and the openpty mechanisms are available, ptmx is used both the ptmx and the openpty mechanisms are available, ptmx is used
(POSIX)\&. (POSIX)\&. In the second form, the link option is
already integrated as a parameter\&.
.br .br
Option groups: FD,NAMED,PTY,TERMIOS Option groups: FD,NAMED,PTY,TERMIOS
.br .br
@ -618,7 +582,7 @@ PIPE,
EXEC, SYSTEM EXEC, SYSTEM
.IP "\fB\f(CWREADLINE\fP\fP" .IP "\fB\f(CWREADLINE\fP\fP"
Uses GNU readline and history on stdio to allow editing and reusing input Uses GNU readline and history on stdio to allow editing and reusing input
lines (example)\&. This requires the GNU readline and lines\&. This requires the GNU readline and
history libraries\&. Note that stdio should be a (pseudo) terminal device, history libraries\&. Note that stdio should be a (pseudo) terminal device,
otherwise readline does not seem to work\&. otherwise readline does not seem to work\&.
.br .br
@ -635,7 +599,7 @@ Connects via <socks-server> [IP address]
to <host> [IPv4 address] to <host> [IPv4 address]
on <port> [TCP service], on <port> [TCP service],
using socks version 4 protocol over IP version 4 or 6 depending on address specification, name resolution, or option using socks version 4 protocol over IP version 4 or 6 depending on address specification, name resolution, or option
pf (example)\&. pf\&.
.br .br
Option groups: FD,SOCKET,IP4,IP6,TCP,SOCKS4,RETRY Option groups: FD,SOCKET,IP4,IP6,TCP,SOCKS4,RETRY
.br .br
@ -743,7 +707,7 @@ TCP-LISTEN,
UDP, UDP,
UNIX-CONNECT UNIX-CONNECT
.IP "\fB\f(CWTCP4:<host>:<port>\fP\fP" .IP "\fB\f(CWTCP4:<host>:<port>\fP\fP"
Like TCP, but only supports IPv4 protocol (example)\&. Like TCP, but only supports IPv4 protocol\&.
.br .br
Option groups: FD,SOCKET,IP4,TCP,RETRY Option groups: FD,SOCKET,IP4,TCP,RETRY
.br .br
@ -783,7 +747,7 @@ UNIX-LISTEN,
OPENSSL-LISTEN OPENSSL-LISTEN
.IP "\fB\f(CWTCP4-LISTEN:<port>\fP\fP" .IP "\fB\f(CWTCP4-LISTEN:<port>\fP\fP"
Like TCP-LISTEN, but only supports IPv4 Like TCP-LISTEN, but only supports IPv4
protocol (example)\&. protocol\&.
.br .br
Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4,TCP,RETRY Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4,TCP,RETRY
.br .br
@ -796,23 +760,7 @@ ipv6only
.br .br
Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6,TCP,RETRY Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6,TCP,RETRY
.br .br
.IP "\fB\f(CWTUN:<if-addr>/<bits>\fP\fP" .IP
Creates a Linux TUN/TAP device and assignes to it the address and netmask
defined by the parameters\&. The resulting network interface is ready for use
by other processes; socat serves its "wire side"\&. This address requires read
and write access to the tunnel cloning device, usually \f(CW/dev/net/tun\fP\&.
.br
Option groups: FD,NAMED,OPEN,TUN
.br
Useful options:
iff-up,
tun-device,
tun-name,
tun-type,
iff-no-pi
.br
See also:
ip-recv
.IP "\fB\f(CWUDP:<host>:<port>\fP\fP" .IP "\fB\f(CWUDP:<host>:<port>\fP\fP"
Connects to <port> [UDP service] on Connects to <port> [UDP service] on
<host> [IP address] using UDP/IP version 4 or 6 <host> [IP address] using UDP/IP version 4 or 6
@ -849,60 +797,14 @@ Like UDP, but only supports IPv6 protocol\&.
.br .br
Option groups: FD,SOCKET,IP6 Option groups: FD,SOCKET,IP6
.br .br
.IP "\fB\f(CWUDP-DATAGRAM:<address>:<port>\fP\fP" .IP
Sends outgoing data to the specified address which may in particular be a
broadcast or multicast address\&. Packets arriving on the local socket are
checked for the correct remote port and if their source addresses match
eventual RANGE or TCPWRAP
options\&. This address type can for example be used for implementing
symmetric or asymmetric broadcast or multicast communications\&.
.br
Option groups: FD,SOCKET,IP4,IP6,RANGE
.br
Useful options:
range,
tcpwrap,
broadcast,
ip-multicast-loop,
ip-multicast-ttl,
ip-multicast-if,
ip-add-membership,
ttl,
tos,
bind,
sourceport,
pf
.br
See also:
UDP4-DATAGRAM,
UDP6-DATAGRAM,
UDP-SENDTO,
UDP-RECVFROM,
UDP-RECV,
UDP-CONNECT,
UDP-LISTEN,
IP-DATAGRAM
.IP "\fB\f(CWUDP4-DATAGRAM:<address>:<port>\fP\fP"
Like UDP-DATAGRAM, but only supports IPv4
protocol (example1,
example2)\&.
.br
Option groups: FD, SOCKET,
IP4, RANGE
.IP "\fB\f(CWUDP6-DATAGRAM:<address>:<port>\fP\fP"
Like UDP-DATAGRAM, but only supports IPv6
protocol\&.
.br
Option groups: FD,SOCKET,
IP6,RANGE
.IP "\fB\f(CWUDP-LISTEN:<port>\fP\fP" .IP "\fB\f(CWUDP-LISTEN:<port>\fP\fP"
Waits for a UDP/IP packet arriving on <port> Waits for a UDP/IP packet arriving on <port>
[UDP service] and `connects\' back to sender\&. [UDP service] and `connects\' back to sender\&.
The accepted IP version is 4 or the one specified with option The accepted IP version is 4 or the one specified with option
pf\&. pf\&.
Please note that, Please note that,
due to UDP protocol properties, no real connection is established; data has due to UDP protocol properties, no real connection is established; data has to arrive from the peer first, and no end-of-file condition can be
to arrive from the peer first, and no end-of-file condition can be
transported\&. Note that opening transported\&. Note that opening
this address usually blocks until a client connects\&. this address usually blocks until a client connects\&.
.br .br
@ -931,14 +833,13 @@ protocol\&.
.br .br
Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6 Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6
.br .br
.IP
.IP "\fB\f(CWUDP-SENDTO:<host>:<port>\fP\fP" .IP "\fB\f(CWUDP-SENDTO:<host>:<port>\fP\fP"
Communicates with the specified peer socket, defined by <port> [UDP Communicates with the specified peer socket, defined by <port> [UDP service] on
service] on
<host> [IP address], using UDP/IP version 4 or 6 <host> [IP address], using UDP/IP version 4 or 6
depending on address specification, name resolution, or option depending on address specification, name resolution, or option
pf\&. It sends packets to and receives packets pf\&. It sends packets to and receives packets from that peer socket only\&.
from that peer socket only\&. This is effectively a datagram client\&.
This address effectively implements a datagram client\&.
It works well with socat UDP-RECVFROM and UDP-RECV address peers\&. It works well with socat UDP-RECVFROM and UDP-RECV address peers\&.
.br .br
Option groups: FD,SOCKET,IP4,IP6 Option groups: FD,SOCKET,IP4,IP6
@ -959,23 +860,19 @@ UDP-CONNECT,
UDP-LISTEN, UDP-LISTEN,
IP-SENDTO IP-SENDTO
.IP "\fB\f(CWUDP4-SENDTO:<host>:<port>\fP\fP" .IP "\fB\f(CWUDP4-SENDTO:<host>:<port>\fP\fP"
Like UDP-SENDTO, but only supports IPv4 Like UDP-SENDTO, but only supports IPv4 protocol\&.
protocol\&.
.br .br
Option groups: FD,SOCKET,IP4 Option groups: FD,SOCKET,IP4
.IP "\fB\f(CWUDP6-SENDTO:<host>:<port>\fP\fP" .IP "\fB\f(CWUDP6-SENDTO:<host>:<port>\fP\fP"
Like UDP-SENDTO, but only supports IPv6 Like UDP-SENDTO, but only supports IPv6 protocol\&.
protocol\&.
.br .br
Option groups: FD,SOCKET,IP6 Option groups: FD,SOCKET,IP6
.IP .IP
.IP "\fB\f(CWUDP-RECVFROM:<port>\fP\fP" .IP "\fB\f(CWUDP-RECVFROM:<port>\fP\fP"
Creates a UDP socket on <port> [UDP service] using Creates a UDP socket on <port> [UDP service] using UDP/IP version 4 or 6
UDP/IP version 4 or 6
depending on option pf\&. depending on option pf\&.
It receives one packet from an unspecified peer and may send one or more It receives one packet from an unspecified peer and may send one or more
answer packets to that peer\&. This mode is particularly useful with fork answer packets to that peer\&. This mode is particularly useful with fork option
option
where each arriving packet - from arbitrary peers - is handled by its own sub where each arriving packet - from arbitrary peers - is handled by its own sub
process\&. This allows a behaviour similar to typical UDP based servers like ntpd process\&. This allows a behaviour similar to typical UDP based servers like ntpd
or named\&. This address works well with socat SENDTO address peers\&. or named\&. This address works well with socat SENDTO address peers\&.
@ -1012,7 +909,8 @@ Option groups: FD,SOCKET,IP6,CHILD,RANGE
Creates a UDP socket on <port> [UDP service] using UDP/IP version 4 or 6 Creates a UDP socket on <port> [UDP service] using UDP/IP version 4 or 6
depending on option pf\&. depending on option pf\&.
It receives packets from multiple unspecified peers and merges the data\&. It receives packets from multiple unspecified peers and merges the data\&.
No replies are possible\&. It works well with, e\&.g\&., socat UDP-SENDTO address peers; it behaves similar to a syslog server\&. No replies are possible\&. It can be, e\&.g\&., addressed by socat UDP-SENDTO address peers\&.
This address works well with socat SENDTO address peers; it behaves similar to a syslog server\&.
.br .br
Option groups: FD,SOCKET,IP4,IP6,RANGE Option groups: FD,SOCKET,IP4,IP6,RANGE
.br .br
@ -1050,9 +948,7 @@ if <filename> is not a UNIX domain socket, this is an error;
if <filename> is a UNIX domain socket, but no process is listening, this is if <filename> is a UNIX domain socket, but no process is listening, this is
an error\&. an error\&.
.br .br
Option groups: FD,SOCKET, Option groups: FD,SOCKET,NAMED,RETRY
NAMED,RETRY,
UNIX
.br .br
) )
Useful options: Useful options:
@ -1071,12 +967,9 @@ If <filename> exists and is a UNIX domain socket, binding to the address
fails (use option unlink-early!)\&. fails (use option unlink-early!)\&.
Note that opening this address usually blocks until a client connects\&. Note that opening this address usually blocks until a client connects\&.
Beginning with socat version 1\&.4\&.3, the file system entry is removed when Beginning with socat version 1\&.4\&.3, the file system entry is removed when
this address is closed (but see option unlink-close) (example)\&. this address is closed (but see option unlink-close)\&.
.br .br
Option groups: FD,SOCKET, Option groups: FD,SOCKET,NAMED,LISTEN,CHILD,RETRY
NAMED,LISTEN,
CHILD,RETRY,
UNIX
.br .br
Useful options: Useful options:
fork, fork,
@ -1097,8 +990,7 @@ Communicates with the specified peer socket, defined by [<filename>] assuming it
It sends packets to and receives packets from that peer socket only\&. It sends packets to and receives packets from that peer socket only\&.
It works well with socat UNIX-RECVFROM and UNIX-RECV address peers\&. It works well with socat UNIX-RECVFROM and UNIX-RECV address peers\&.
.br .br
Option groups: FD,SOCKET, Option groups: FD,SOCKET,NAMED
NAMED,UNIX
.br .br
Useful options: Useful options:
bind bind
@ -1116,9 +1008,7 @@ Receives one packet and may send one or more answer packets to that peer\&.
This mode is particularly useful with fork option where each arriving packet - from arbitrary peers - is handled by its own sub process\&. This mode is particularly useful with fork option where each arriving packet - from arbitrary peers - is handled by its own sub process\&.
This address works well with socat UNIX-SENDTO address peers\&. This address works well with socat UNIX-SENDTO address peers\&.
.br .br
Option groups: FD,SOCKET, Option groups: FD,SOCKET,NAMED,CHILD
NAMED,CHILD,
UNIX
.br .br
Useful options: Useful options:
fork fork
@ -1135,8 +1025,7 @@ Creates a UNIX domain datagram socket [<filename>]\&.
Receives packets from multiple unspecified peers and merges the data\&. Receives packets from multiple unspecified peers and merges the data\&.
No replies are possible\&. It can be, e\&.g\&., addressed by socat UNIX-SENDTO address peers\&. No replies are possible\&. It can be, e\&.g\&., addressed by socat UNIX-SENDTO address peers\&.
It behaves similar to a syslog server\&. It behaves similar to a syslog server\&.
Option groups: FD,SOCKET, Option groups: FD,SOCKET,NAMED
NAMED,UNIX
.br .br
See also: See also:
UNIX-SENDTO, UNIX-SENDTO,
@ -1145,14 +1034,13 @@ UNIX-LISTEN,
UDP-RECV, UDP-RECV,
IP-RECV IP-RECV
.IP .IP
.IP "\fB\f(CWUNIX-CLIENT:<filename>\fP\fP" .IP "\fB\f(CWUNIX:<filename>\fP\fP"
Communicates with the specified peer socket, defined by Communicates with the specified peer socket, defined by
[<filename>] assuming it is a UNIX domain socket\&. [<filename>] assuming it is a UNIX domain socket\&.
It first tries to connect and, if that fails, assumes it is a datagram It first tries to connect and, if that fails, assumes it is a datagram
socket, thus supporting both types\&. socket, thus supporting both types\&.
.br .br
Option groups: FD,SOCKET, Option groups: FD,SOCKET,NAMED
NAMED,UNIX
.br .br
Useful options: Useful options:
bind bind
@ -1161,19 +1049,6 @@ See also:
UNIX-CONNECT, UNIX-CONNECT,
UNIX-SENDTO, UNIX-SENDTO,
GOPEN GOPEN
.IP
.IP "\fB\f(CWABSTRACT-CONNECT:<string>\fP\fP"
.IP "\fB\f(CWABSTRACT-LISTEN:<string>\fP\fP"
.IP "\fB\f(CWABSTRACT-SENDTO:<string>\fP\fP"
.IP "\fB\f(CWABSTRACT-RECVFROM:<string>\fP\fP"
.IP "\fB\f(CWABSTRACT-RECV:<string>\fP\fP"
.IP "\fB\f(CWABSTRACT-CLIENT:<string>\fP\fP"
The ABSTRACT addresses are almost identical to the related UNIX addresses
except that they do not address file system based sockets but an alternate
UNIX domain address space\&. To archieve this the socket address strings are
prefixed with "\e0" internally\&. This feature is available (only?) on Linux\&.
Option groups are the same as with the related UNIX addresses, except that
the ABSTRACT addresses are not member of the NAMED group\&.
.PP .PP
.SH "ADDRESS OPTIONS" .SH "ADDRESS OPTIONS"
.PP .PP
@ -1248,37 +1123,20 @@ internally handles
this flag for the fds it controls, so in most cases there will be no need to this flag for the fds it controls, so in most cases there will be no need to
apply this option\&. apply this option\&.
.IP "\fB\f(CWsetlk\fP\fP" .IP "\fB\f(CWsetlk\fP\fP"
Tries to set a discretionary write lock to the whole file using the \f(CWfcntl(fd, Tries to set a discretionary lock to the whole file using the \f(CWfcntl(fd,
F_SETLK, \&.\&.\&.)\fP system call\&. If the file is already locked, this call results F_SETLK, \&.\&.\&.)\fP system call\&. If the file is already locked, this call results
in an error\&. in an error\&.
On Linux, when the file permissions for group are "S" (g-x,g+s), and the
file system is locally mounted with the "mand" option, the lock is
mandatory, i\&.e\&. prevents other processes from opening the file\&.
.IP "\fB\f(CWsetlkw\fP\fP" .IP "\fB\f(CWsetlkw\fP\fP"
Tries to set a discretionary waiting write lock to the whole file using the Tries to set a discretionary waiting lock to the whole file using the
\f(CWfcntl(fd, F_SETLKW, \&.\&.\&.)\fP system call\&. If the file is already locked, \f(CWfcntl(fd, F_SETLKW, \&.\&.\&.)\fP system call\&. If the file is already locked,
this call blocks\&. this call blocks\&.
See option setlk for information about making this
lock mandatory\&.
.IP "\fB\f(CWsetlk-rd\fP\fP"
Tries to set a discretionary read lock to the whole file using the \f(CWfcntl(fd,
F_SETLK, \&.\&.\&.)\fP system call\&. If the file is already write locked, this call
results in an error\&.
See option setlk for information about making this
lock mandatory\&.
.IP "\fB\f(CWsetlkw-rd\fP\fP"
Tries to set a discretionary waiting read lock to the whole file using the
\f(CWfcntl(fd, F_SETLKW, \&.\&.\&.)\fP system call\&. If the file is already write
locked, this call blocks\&.
See option setlk for information about making this
lock mandatory\&.
.IP "\fB\f(CWflock-ex\fP\fP" .IP "\fB\f(CWflock-ex\fP\fP"
Tries to set a blocking exclusive advisory lock to the file using the Tries to set a blocking exclusive advisory lock to the file using the
\f(CWflock(fd, LOCK_EX)\fP system call\&. \fBSocat\fP hangs in this call if the file \f(CWflock(fd, LOCK_EX)\fP system call\&. \fBSocat\fP hangs in this call if the file
is locked by another process\&. is locked by another process\&.
.IP "\fB\f(CWflock-ex-nb\fP\fP" .IP "\fB\f(CWflock-ex-nb\fP\fP"
Tries to set a nonblocking exclusive advisory lock to the file using the Tries to set a nonblocking exclusive advisory lock to the file using the
\f(CWflock(fd, LOCK_EX|LOCK_NB)\fP system call\&. If the file is already locked, \f(CWflock(fd, LOCK_EX)\fP system call\&. If the file is already locked,
this option results in an error\&. this option results in an error\&.
.IP "\fB\f(CWflock-sh\fP\fP" .IP "\fB\f(CWflock-sh\fP\fP"
Tries to set a blocking shared advisory lock to the file using the Tries to set a blocking shared advisory lock to the file using the
@ -1291,7 +1149,7 @@ this option results in an error\&.
.IP "\fB\f(CWlock\fP\fP" .IP "\fB\f(CWlock\fP\fP"
Sets a blocking lock on the file\&. Uses the setlk or flock mechanism Sets a blocking lock on the file\&. Uses the setlk or flock mechanism
depending on availability on the particular platform\&. If both are available, depending on availability on the particular platform\&. If both are available,
the POSIX variant (setlkw) is used\&. the POSIX variant (setlkw) is selected\&.
.IP "\fB\f(CWuser=<user>\fP\fP" .IP "\fB\f(CWuser=<user>\fP\fP"
Sets the <user> (owner) of the stream\&. Sets the <user> (owner) of the stream\&.
If the address is member of the NAMED option group, If the address is member of the NAMED option group,
@ -1336,8 +1194,7 @@ This is useful only on file system entries\&.
.IP "\fB\f(CWappend=<bool>\fP\fP" .IP "\fB\f(CWappend=<bool>\fP\fP"
Always writes data to the actual end of file\&. Always writes data to the actual end of file\&.
If the address is member of the OPEN option group, If the address is member of the OPEN option group,
\fBsocat\fP uses the \f(CWO_APPEND\fP flag with the \f(CWopen()\fP system call \fBsocat\fP uses the \f(CWO_APPEND\fP flag with the \f(CWopen()\fP system call\&.
(example)\&.
Otherwise, \fBsocat\fP applies the \f(CWfcntl(fd, F_SETFL, O_APPEND)\fP call\&. Otherwise, \fBsocat\fP applies the \f(CWfcntl(fd, F_SETFL, O_APPEND)\fP call\&.
.IP "\fB\f(CWnonblock=<bool>\fP\fP" .IP "\fB\f(CWnonblock=<bool>\fP\fP"
Tries to open or use file in nonblocking mode\&. Its only effects are that the Tries to open or use file in nonblocking mode\&. Its only effects are that the
@ -1362,19 +1219,6 @@ when socat is used as a high volume server or proxy where clients often
abort the connection\&. abort the connection\&.
.br .br
This option is experimental\&. This option is experimental\&.
.IP "\fB\f(CWend-close\fP\fP"
Changes the (address dependent) method of ending a connection to just close
the file descriptors\&. This is useful when the connection is to be reused by
or shared with other processes (example)\&.
.br
Normally, socket connections will be ended with \f(CWshutdown(2)\fP which
terminates the socket even if it is shared by multiple processes\&.
\f(CWclose(2)\fP "unlinks" the socket from the process but keeps it active as
long as there are still links from other processes\&.
.br
Similarly, when an address of type EXEC or SYSTEM is ended, socat usually
will explicitely kill the sub process\&. With this option, it will just close
the file descriptors\&.
.PP .PP
.br .br
.PP .PP
@ -1432,7 +1276,7 @@ E\&.g\&., option `creat\' sets the \f(CWO_CREAT\fP flag\&.
See also options append and See also options append and
nonblock\&. nonblock\&.
.IP "\fB\f(CWcreat=<bool>\fP\fP" .IP "\fB\f(CWcreat=<bool>\fP\fP"
Creates the file if it does not exist (example)\&. Creates the file if it does not exist\&.
.IP "\fB\f(CWdsync=<bool>\fP\fP" .IP "\fB\f(CWdsync=<bool>\fP\fP"
Blocks \f(CWwrite()\fP calls until metainfo is physically written to media\&. Blocks \f(CWwrite()\fP calls until metainfo is physically written to media\&.
.IP "\fB\f(CWexcl=<bool>\fP\fP" .IP "\fB\f(CWexcl=<bool>\fP\fP"
@ -1513,7 +1357,7 @@ option FORK,
these options apply to the child processes instead of the main socat process\&. these options apply to the child processes instead of the main socat process\&.
.IP "\fB\f(CWchroot=<directory>\fP\fP" .IP "\fB\f(CWchroot=<directory>\fP\fP"
Performs a \f(CWchroot()\fP operation to <directory> Performs a \f(CWchroot()\fP operation to <directory>
after processing the address (example)\&. This call might require root privilege\&. after processing the address\&. This call might require root privilege\&.
.IP "\fB\f(CWchroot-early=<directory>\fP\fP" .IP "\fB\f(CWchroot-early=<directory>\fP\fP"
Performs a \f(CWchroot()\fP operation to <directory> Performs a \f(CWchroot()\fP operation to <directory>
before opening the address\&. This call might require root privilege\&. before opening the address\&. This call might require root privilege\&.
@ -1531,11 +1375,11 @@ Changes the <user> (owner) of the process before opening
the address\&. This call might require root privilege\&. the address\&. This call might require root privilege\&.
.IP "\fB\f(CWsu=<user>\fP\fP" .IP "\fB\f(CWsu=<user>\fP\fP"
Changes the <user> (owner) and groups of the process after Changes the <user> (owner) and groups of the process after
processing the address (example)\&. This call might require root privilege\&. processing the address\&. This call might require root privilege\&.
.IP "\fB\f(CWsu-d=<user>\fP\fP" .IP "\fB\f(CWsu-d=<user>\fP\fP"
Short name for \fB\f(CWsubstuser-delayed\fP\fP\&. Short name for \fB\f(CWsubstuser-delayed\fP\fP\&.
Changes the <user> Changes the <user>
(owner) and groups of the process after processing the address (example)\&. (owner) and groups of the process after processing the address\&.
The user and his groups are retrieved \fIbefore\fP a possible The user and his groups are retrieved \fIbefore\fP a possible
\f(CWchroot()\fP\&. This call might require root privilege\&. \f(CWchroot()\fP\&. This call might require root privilege\&.
.IP "\fB\f(CWsetpgid=<pid_t>\fP\fP" .IP "\fB\f(CWsetpgid=<pid_t>\fP\fP"
@ -1544,7 +1388,7 @@ Makes the process a member of the specified process group
is given, or if the value is 0 or 1, the process becomes leader of a new is given, or if the value is 0 or 1, the process becomes leader of a new
process group\&. process group\&.
.IP "\fB\f(CWsetsid\fP\fP" .IP "\fB\f(CWsetsid\fP\fP"
Makes the process the leader of a new session (example)\&. Makes the process the leader of a new session\&.
.PP .PP
.br .br
.PP .PP
@ -1552,7 +1396,7 @@ Makes the process the leader of a new session (example)\&.
.PP .PP
These options apply to the readline address type\&. These options apply to the readline address type\&.
.IP "\fB\f(CWhistory=<filename>\fP\fP" .IP "\fB\f(CWhistory=<filename>\fP\fP"
Reads and writes history from/to <filename> (example)\&. Reads and writes history from/to <filename>\&.
.IP "\fB\f(CWnoprompt\fP\fP" .IP "\fB\f(CWnoprompt\fP\fP"
Since version 1\&.4\&.0, socat per default tries to determine a prompt - Since version 1\&.4\&.0, socat per default tries to determine a prompt -
that is then passed to the readline call - by remembering the last that is then passed to the readline call - by remembering the last
@ -1566,7 +1410,6 @@ The prompt is defined as the text that was output to the readline address
after the lastest newline character and before an input character was after the lastest newline character and before an input character was
typed\&. The pattern is a regular expression, e\&.g\&. typed\&. The pattern is a regular expression, e\&.g\&.
"^[Pp]assword:\&.*$" or "([Uu]ser:|[Pp]assword:)"\&. See regex(7) for details\&. "^[Pp]assword:\&.*$" or "([Uu]ser:|[Pp]assword:)"\&. See regex(7) for details\&.
(example)
.IP "\fB\f(CWprompt=<string>\fP\fP" .IP "\fB\f(CWprompt=<string>\fP\fP"
Passes the string as prompt to the readline function\&. readline prints this Passes the string as prompt to the readline function\&. readline prints this
prompt when stepping through the history\&. If this string matches a constant prompt when stepping through the history\&. If this string matches a constant
@ -1586,11 +1429,11 @@ Converts the default line termination character NL (\'\en\', 0x0a) to/from CR
(\'\er\', 0x0d) when writing/reading on this channel\&. (\'\er\', 0x0d) when writing/reading on this channel\&.
.IP "\fB\f(CWcrnl\fP\fP" .IP "\fB\f(CWcrnl\fP\fP"
Converts the default line termination character NL (\'\en\', 0x0a) to/from CRNL Converts the default line termination character NL (\'\en\', 0x0a) to/from CRNL
("\er\en", 0x0d0a) when writing/reading on this channel (example)\&. ("\er\en", 0x0d0a) when writing/reading on this channel\&.
Note: socat simply strips all CR characters\&. Note: socat simply strips all CR characters\&.
.IP "\fB\f(CWignoreeof\fP\fP" .IP "\fB\f(CWignoreeof\fP\fP"
When EOF occurs on this channel, \fBsocat\fP ignores it and tries to read more When EOF occurs on this channel, \fBsocat\fP ignores it and tries to read more
data (like "tail -f") (example)\&. data (like "tail -f")\&.
.IP "\fB\f(CWreadbytes=<bytes>\fP\fP" .IP "\fB\f(CWreadbytes=<bytes>\fP\fP"
\fBsocat\fP reads only so many bytes from this address (the address provides \fBsocat\fP reads only so many bytes from this address (the address provides
only so many bytes for transfer and pretends to be at EOF afterwards)\&. only so many bytes for transfer and pretends to be at EOF afterwards)\&.
@ -1610,7 +1453,7 @@ These options are intended for all kinds of sockets, e\&.g\&. IP or UNIX domain\
.IP "\fB\f(CWbind=<sockname>\fP\fP" .IP "\fB\f(CWbind=<sockname>\fP\fP"
Binds the socket to the given socket address using the \f(CWbind()\fP system Binds the socket to the given socket address using the \f(CWbind()\fP system
call\&. The form of <sockname> is socket domain dependent: call\&. The form of <sockname> is socket domain dependent:
IP4 and IP6 allow the form [hostname|hostaddress][:(service|port)] (example), IP4 and IP6 allow the form [hostname|hostaddress][:(service|port)],
UNIX domain sockets require <filename>\&. UNIX domain sockets require <filename>\&.
.IP "\fB\f(CWconnect-timeout=<seconds>\fP\fP" .IP "\fB\f(CWconnect-timeout=<seconds>\fP\fP"
Abort the connection attempt after <seconds> [timeval] Abort the connection attempt after <seconds> [timeval]
@ -1653,7 +1496,7 @@ the socket layer will pass the buffered data to \fBsocat\fP\&.
Sets the receive timeout [timeval]\&. Sets the receive timeout [timeval]\&.
.IP "\fB\f(CWreuseaddr\fP\fP" .IP "\fB\f(CWreuseaddr\fP\fP"
Allows other sockets to bind to an address even if parts of it (e\&.g\&. the Allows other sockets to bind to an address even if parts of it (e\&.g\&. the
local port) are already in use by \fBsocat\fP (example)\&. local port) are already in use by \fBsocat\fP\&.
.IP "\fB\f(CWsndbuf=<bytes>\fP\fP" .IP "\fB\f(CWsndbuf=<bytes>\fP\fP"
Sets the size of the send buffer after the \f(CWsocket()\fP call to Sets the size of the send buffer after the \f(CWsocket()\fP call to
<bytes> [int]\&. <bytes> [int]\&.
@ -1676,14 +1519,6 @@ something like "ip4" or "ip6"\&.
.PP .PP
.br .br
.PP .PP
\fI\fBUNIX option group\fP\fP
.PP
These options apply to UNIX domain based addresses\&.
.IP "\fB\f(CWunix-tightsocklen=[0|1]\fP\fP"
On socket operations, pass a socket address length that does not include the
whole \f(CWstruct sockaddr_un\fP record but (besides other components) only
the relevant part of the filename or abstract string\&. Default is 1\&.
.PP
\fI\fBIP4 and IP6 option groups\fP\fP \fI\fBIP4 and IP6 option groups\fP\fP
.PP .PP
These options can be used with IPv4 and IPv6 based sockets\&. These options can be used with IPv4 and IPv6 based sockets\&.
@ -1706,26 +1541,6 @@ IP options are defined in RFC 791\&.
.IP "\fB\f(CWmtudiscover=<0|1|2>\fP\fP" .IP "\fB\f(CWmtudiscover=<0|1|2>\fP\fP"
Takes 0, 1, 2 to never, want, or always use path MTU discover on this Takes 0, 1, 2 to never, want, or always use path MTU discover on this
socket\&. socket\&.
.IP "\fB\f(CWip-add-membership=<multicast-address:interface-address>\fP\fP"
.IP "\fB\f(CWip-add-membership=<multicast-address:interface-name>\fP\fP"
.IP "\fB\f(CWip-add-membership=<multicast-address:interface-index>\fP\fP"
.IP "\fB\f(CWip-add-membership=<multicast-address:interface-address:interface-name>\fP\fP"
.IP "\fB\f(CWip-add-membership=<multicast-address:interface-address:interface-index>\fP\fP"
Makes the socket member of the specified multicast group\&. This is currently
only implemented for IPv4\&. The option takes the IP address of the multicast
group and info about the desired network interface\&. The most common syntax
is the first one, while the others are only available on systems that
provide \f(CWstruct mreqn\fP (Linux)\&.
.br
The indices of active network interfaces can be shown using the utility
\fBprocan\fP\&.
dif(\fB\f(CWip-multicast-if=<hostname>\fP\fP)
Specifies hostname or address of the network interface to be used for
multicast traffic\&.
dif(\fB\f(CWip-multicast-loop=<bool>\fP\fP)
Specifies if outgoing multicast traffic should loop back to the interface\&.
dif(\fB\f(CWip-multicast-ttl=<byte>\fP\fP)
Sets the TTL used for outgoing multicast traffic\&. Default is 1\&.
.IP "\fB\f(CWres-debug\fP\fP" .IP "\fB\f(CWres-debug\fP\fP"
.IP "\fB\f(CWres-aaonly\fP\fP" .IP "\fB\f(CWres-aaonly\fP\fP"
.IP "\fB\f(CWres-usevc\fP\fP" .IP "\fB\f(CWres-usevc\fP\fP"
@ -1777,8 +1592,7 @@ Sets the time to keep the socket in FIN-WAIT-2 state to <seconds>
.IP "\fB\f(CWmss=<bytes>\fP\fP" .IP "\fB\f(CWmss=<bytes>\fP\fP"
Sets the MSS (maximum segment size) after the \f(CWsocket()\fP call to <bytes> Sets the MSS (maximum segment size) after the \f(CWsocket()\fP call to <bytes>
[int]\&. This [int]\&. This
value is then proposed to the peer with the SYN or SYN/ACK packet value is then proposed to the peer with the SYN or SYN/ACK packet\&.
(example)\&.
.IP "\fB\f(CWmss-late=<bytes>\fP\fP" .IP "\fB\f(CWmss-late=<bytes>\fP\fP"
Sets the MSS of the socket after connection has been established to <bytes> Sets the MSS of the socket after connection has been established to <bytes>
[int]\&. [int]\&.
@ -1829,7 +1643,7 @@ thus can be used with UDP and TCP, client and server addresses\&.
For outgoing (client) TCP and UDP connections, it sets the source For outgoing (client) TCP and UDP connections, it sets the source
<port> using an extra \f(CWbind()\fP call\&. <port> using an extra \f(CWbind()\fP call\&.
With TCP or UDP listen addresses, socat immediately shuts down the With TCP or UDP listen addresses, socat immediately shuts down the
connection if the client does not use this sourceport (example)\&. connection if the client does not use this sourceport\&.
.IP "\fB\f(CWlowport\fP\fP" .IP "\fB\f(CWlowport\fP\fP"
Outgoing (client) TCP and UDP connections with this option use Outgoing (client) TCP and UDP connections with this option use
an unused random source port between 640 and 1023 incl\&. On UNIX class operating an unused random source port between 640 and 1023 incl\&. On UNIX class operating
@ -1849,7 +1663,7 @@ Overrides the default "socks" service or port 1080 for the socks server
port with <TCP service>\&. port with <TCP service>\&.
.IP "\fB\f(CWsocksuser=<user>\fP\fP" .IP "\fB\f(CWsocksuser=<user>\fP\fP"
Sends the <user> [string] in the username field to the Sends the <user> [string] in the username field to the
socks server\&. Default is the actual user name ($LOGNAME or $USER) (example)\&. socks server\&. Default is the actual user name ($LOGNAME or $USER)\&.
.PP .PP
.br .br
.PP .PP
@ -1877,20 +1691,19 @@ server unencrypted (base64 encoded) and might be sniffed\&.
.IP "\fB\f(CWresolve\fP\fP" .IP "\fB\f(CWresolve\fP\fP"
Per default, socat sends to the proxy a CONNECT request containing the Per default, socat sends to the proxy a CONNECT request containing the
target hostname\&. With this option, socat resolves the hostname locally and target hostname\&. With this option, socat resolves the hostname locally and
sends the IP address\&. Please note that, according to RFC 2396, only name sends the IP address\&.
resolution to IPv4 addresses is implemented\&.
.PP .PP
.br .br
.PP .PP
\fI\fBRANGE option group\fP\fP \fI\fBRANGE option group\fP\fP
.PP .PP
These options check if a connecting client should be granted access\&. They can These options check if a connecting client is granted access\&. They can be
be applied to listening and receiving network sockets\&. tcp-wrappers options applied to listening and receiving network sockets\&. tcp-wrappers options fall
fall into this group\&. into this group\&.
.IP "\fB\f(CWrange=<address-range>\fP\fP" .IP "\fB\f(CWrange=<address-range>\fP\fP"
After accepting a connection, tests if the peer is within \fIrange\fP\&. For After accepting a connection, tests if the peer is within \fIrange\fP\&. For
IPv4 addresses, address-range takes the form address/bits, e\&.g\&. IPv4 addresses, address-range takes the form ww\&.xx\&.yy\&.zz/bits, e\&.g\&.
10\&.0\&.0\&.0/8, or address:mask, e\&.g\&. 10\&.0\&.0\&.0:255\&.0\&.0\&.0 (example); for IPv6, it is [ip6-address/bits], e\&.g\&. [::1/128]\&. 10\&.0\&.0\&.0/8; for IPv6, it is [ip6-address/bits], e\&.g\&. [::1/128]\&.
If the client address does not match, \fBsocat\fP issues a warning and keeps If the client address does not match, \fBsocat\fP issues a warning and keeps
listening/receiving\&. listening/receiving\&.
.IP "\fB\f(CWtcpwrap[=<name>]\fP\fP" .IP "\fB\f(CWtcpwrap[=<name>]\fP\fP"
@ -1898,7 +1711,7 @@ Uses Wietse Venema\'s libwrap (tcpd) library to determine
if the client is allowed to connect\&. The configuration files are if the client is allowed to connect\&. The configuration files are
/etc/hosts\&.allow and /etc/hosts\&.deny per default, see "man 5 hosts_access" /etc/hosts\&.allow and /etc/hosts\&.deny per default, see "man 5 hosts_access"
for more information\&. The optional <name> (type string) for more information\&. The optional <name> (type string)
is passed to the wrapper functions as daemon process name (example)\&. is passed to the wrapper functions as daemon process name\&.
If omitted, the basename of socats invocation (argv[0]) is passed\&. If omitted, the basename of socats invocation (argv[0]) is passed\&.
If both tcpwrap and range options are applied to an address, both If both tcpwrap and range options are applied to an address, both
conditions must be fulfilled to allow the connection\&. conditions must be fulfilled to allow the connection\&.
@ -1927,7 +1740,7 @@ Options for addresses with multiple connections via child processes\&.
.IP "\fB\f(CWfork\fP\fP" .IP "\fB\f(CWfork\fP\fP"
After establishing a connection, handles its channel in a child process and After establishing a connection, handles its channel in a child process and
keeps the parent process attempting to produce more connections, either by keeps the parent process attempting to produce more connections, either by
listening or by connecting in a loop (example)\&. listening or by connecting in a loop\&.
.br .br
SSL-CONNECT and SSL-LISTEN differ in when they actually fork off the child: SSL-CONNECT and SSL-LISTEN differ in when they actually fork off the child:
SSL-LISTEN forks \fIbefore\fP the SSL handshake, while SSL-CONNECT forks SSL-LISTEN forks \fIbefore\fP the SSL handshake, while SSL-CONNECT forks
@ -1991,22 +1804,22 @@ created by opening \fB/dev/ptmx\fP or \fB/dev/ptc\fP instead of the default
Establishes communication with the sub process using a pseudo terminal Establishes communication with the sub process using a pseudo terminal
instead of a socket pair\&. Creates the pty with an available mechanism\&. If instead of a socket pair\&. Creates the pty with an available mechanism\&. If
openpty and ptmx are both available, it uses ptmx because this is POSIX openpty and ptmx are both available, it uses ptmx because this is POSIX
compliant (example)\&. compliant\&.
.IP "\fB\f(CWctty\fP\fP" .IP "\fB\f(CWctty\fP\fP"
Makes the pty the controlling tty of the sub process (example)\&. Makes the pty the controlling tty of the sub process\&.
.IP "\fB\f(CWstderr\fP\fP" .IP "\fB\f(CWstderr\fP\fP"
Directs stderr of the sub process to its output channel by making stderr a Directs stderr of the sub process to its output channel by making stderr a
\f(CWdup()\fP of stdout (example)\&. \f(CWdup()\fP of stdout\&.
.IP "\fB\f(CWfdin=<fdnum>\fP\fP" .IP "\fB\f(CWfdin=<fdnum>\fP\fP"
Assigns the sub processes input channel to its file descriptor Assigns the sub processes input channel to its file descriptor
<fdnum> <fdnum>
instead of stdin (0)\&. The program started from the subprocess has to use instead of stdin (0)\&. The program started from the subprocess has to use
this fd for reading data from \fBsocat\fP (example)\&. this fd for reading data from \fBsocat\fP\&.
.IP "\fB\f(CWfdout=<fdnum>\fP\fP" .IP "\fB\f(CWfdout=<fdnum>\fP\fP"
Assigns the sub processes output channel to its file descriptor Assigns the sub processes output channel to its file descriptor
<fdnum> <fdnum>
instead of stdout (1)\&. The program started from the subprocess has to use instead of stdout (1)\&. The program started from the subprocess has to use
this fd for writing data to \fBsocat\fP (example)\&. this fd for writing data to \fBsocat\fP\&.
.IP "\fB\f(CWsighup\fP\fP, \fB\f(CWsigint\fP\fP, \fB\f(CWsigquit\fP\fP" .IP "\fB\f(CWsighup\fP\fP, \fB\f(CWsigint\fP\fP, \fB\f(CWsigquit\fP\fP"
Has \fBsocat\fP pass an eventual signal of this type to the sub process\&. Has \fBsocat\fP pass an eventual signal of this type to the sub process\&.
If no address has this option, socat terminates on these signals\&. If no address has this option, socat terminates on these signals\&.
@ -2033,12 +1846,12 @@ Note: On some operating systems, these options may not be
available\&. Use ispeed or ospeed available\&. Use ispeed or ospeed
instead\&. instead\&.
.IP "\fB\f(CWecho=<bool>\fP\fP" .IP "\fB\f(CWecho=<bool>\fP\fP"
Enables or disables local echo (example)\&. Enables or disables local echo\&.
.IP "\fB\f(CWicanon=<bool>\fP\fP" .IP "\fB\f(CWicanon=<bool>\fP\fP"
Sets or clears canonical mode, enabling line buffering and some special Sets or clears canonical mode, enabling line buffering and some special
characters\&. characters\&.
.IP "\fB\f(CWraw\fP\fP" .IP "\fB\f(CWraw\fP\fP"
Sets raw mode, thus passing input and output almost unprocessed (example)\&. Sets raw mode, thus passing input and output almost unprocessed\&.
.IP "\fB\f(CWignbrk=<bool>\fP\fP" .IP "\fB\f(CWignbrk=<bool>\fP\fP"
Ignores or interpretes the BREAK character (e\&.g\&., ^C) Ignores or interpretes the BREAK character (e\&.g\&., ^C)
.IP "\fB\f(CWbrkint=<bool>\fP\fP" .IP "\fB\f(CWbrkint=<bool>\fP\fP"
@ -2174,8 +1987,7 @@ Generates a symbolic link that points to the actual pseudo terminal
to solve the problem that ptys are generated with more or less to solve the problem that ptys are generated with more or less
unpredictable names, making it difficult to directly access the socat unpredictable names, making it difficult to directly access the socat
generated pty automatically\&. With this option, the user can specify a "fix" generated pty automatically\&. With this option, the user can specify a "fix"
point in the file hierarchy that helps him to access the actual pty point in the file hierarchy that helps him to access the actual pty\&.
(example)\&.
Beginning with \fBsocat\fP version 1\&.4\&.3, the symbolic link is removed when Beginning with \fBsocat\fP version 1\&.4\&.3, the symbolic link is removed when
the address is closed (but see option unlink-close)\&. the address is closed (but see option unlink-close)\&.
.IP "\fB\f(CWwait-slave\fP\fP" .IP "\fB\f(CWwait-slave\fP\fP"
@ -2233,8 +2045,9 @@ this option is not provided\&.
.IP "\f(CWTLSv1\fP" .IP "\f(CWTLSv1\fP"
Select TLS protocol version 1\&. Select TLS protocol version 1\&.
.IP "\fB\f(CWverify=<bool>\fP\fP" .IP "\fB\f(CWverify=<bool>\fP\fP"
Controls check of the peer\'s certificate\&. Default is 1 (true)\&. Disabling Controls check of the peer\'s certificate\&. Default is 1 (true) for client and
verify might open your socket for everyone, making the encryption useless! 0 (false) for server addresses\&. Disabling verify might open your socket for
everyone!
.IP "\fB\f(CWcert=<filename>\fP\fP" .IP "\fB\f(CWcert=<filename>\fP\fP"
Specifies the file with the certificate and private key for authentication\&. Specifies the file with the certificate and private key for authentication\&.
The certificate must be in OpenSSL format (*\&.pem)\&. The certificate must be in OpenSSL format (*\&.pem)\&.
@ -2295,61 +2108,6 @@ Performs an unlimited number of retry attempts\&.
.PP .PP
.br .br
.PP .PP
\fI\fBTUN option group\fP\fP
.PP
Options that control Linux TUN/TAP interface device addresses\&.
.PP
.IP "\fB\f(CWtun-device=<device-file>\fP\fP"
Instructs socat to take another path for the TUN clone device\&. Default is
\f(CW/dev/net/tun\fP\&.
.IP "\fB\f(CWtun-name=<if-name>\fP\fP"
Gives the resulting network interface a specific name instead of the system
generated (tun0, tun1, etc\&.)
.IP "\fB\f(CWtun-type=[tun|tap]\fP\fP"
Sets the type of the TUN device; use this option to generate a TAP
device\&. See the Linux docu for the difference between these types\&.
When you try to establish a tunnel between two TUN devices, their types
should be the same\&.
.IP "\fB\f(CWiff-no-pi\fP\fP"
Sets the IFF_NO_PI flag which controls if the device includes additional
packet information in the tunnel\&.
When you try to establish a tunnel between two TUN devices, these flags
should have the same values\&.
.IP "\fB\f(CWiff-up\fP\fP"
Sets the TUN network interface status UP\&. Strongly recommended\&.
.IP "\fB\f(CWiff-broadcast\fP\fP"
Sets the BROADCAST flag of the TUN network interface\&.
.IP "\fB\f(CWiff-debug\fP\fP"
Sets the DEBUG flag of the TUN network interface\&.
.IP "\fB\f(CWiff-loopback\fP\fP"
Sets the LOOPBACK flag of the TUN network interface\&.
.IP "\fB\f(CWiff-pointopoint\fP\fP"
Sets the POINTOPOINT flag of the TUN device\&.
.IP "\fB\f(CWiff-notrailers\fP\fP"
Sets the NOTRAILERS flag of the TUN device\&.
.IP "\fB\f(CWiff-running\fP\fP"
Sets the RUNNING flag of the TUN device\&.
.IP "\fB\f(CWiff-noarp\fP\fP"
Sets the NOARP flag of the TUN device\&.
.IP "\fB\f(CWiff-promisc\fP\fP"
Sets the PROMISC flag of the TUN device\&.
.IP "\fB\f(CWiff-allmulti\fP\fP"
Sets the ALLMULTI flag of the TUN device\&.
.IP "\fB\f(CWiff-master\fP\fP"
Sets the MASTER flag of the TUN device\&.
.IP "\fB\f(CWiff-slave\fP\fP"
Sets the SLAVE flag of the TUN device\&.
.IP "\fB\f(CWiff-multicast\fP\fP"
Sets the MULTICAST flag of the TUN device\&.
.IP "\fB\f(CWiff-portsel\fP\fP"
Sets the PORTSEL flag of the TUN device\&.
.IP "\fB\f(CWiff-automedia\fP\fP"
Sets the AUTOMEDIA flag of the TUN device\&.
.IP "\fB\f(CWiff-dynamic\fP\fP"
Sets the DYNAMIC flag of the TUN device\&.
.PP
.br
.PP
.SH "DATA VALUES" .SH "DATA VALUES"
.PP .PP
This section explains the different data types that address parameters and This section explains the different data types that address parameters and
@ -2491,7 +2249,7 @@ second connection\&.
\.LP \.LP
\.nf \.nf
\fBsocat -d -d -lmlocal2 \\ \fBsocat -d -d -lmlocal2 \\
TCP4-LISTEN:80,bind=myaddr1,reuseaddr,fork,su=nobody,range=10.0.0.0/8 \\ TCP4-LISTEN:80,bind=myaddr1,su=nobody,fork,range=10.0.0.0/8,reuseaddr \\
TCP4:www.domain.org:80,bind=myaddr2\fP TCP4:www.domain.org:80,bind=myaddr2\fP
\.fi \.fi
.IP .IP
@ -2626,7 +2384,7 @@ pty is required to have ftp issue a prompt\&.
Nevertheless, there may occur some confusion with the password and FTP Nevertheless, there may occur some confusion with the password and FTP
prompts\&. prompts\&.
.IP .IP
(\fB\f(CWsocat PTY,link=$HOME/dev/vmodem0,raw,echo=0,waitslave EXEC:\'"ssh modemserver\&.us\&.org socat - /dev/ttyS0,nonblock,raw,echo=0"\'\fP\fP) .IP "\fB\f(CWsocat PTY,link=$HOME/dev/vmodem0,raw,echo=0,waitslave exec:\'"ssh modemserver\&.us\&.org socat - /dev/ttyS0,nonblock,raw,echo=0"\'\fP\fP"
.IP .IP
Generates a pseudo terminal Generates a pseudo terminal
device (PTY) on the client that can be reached under the device (PTY) on the client that can be reached under the
@ -2649,31 +2407,6 @@ through the proxy daemon listening on port 3128
CONNECT method, where they are authenticated as "user" with "pass" (proxyauth)\&. The proxy CONNECT method, where they are authenticated as "user" with "pass" (proxyauth)\&. The proxy
should establish connections to host www\&.domain\&.org on port 22 then\&. should establish connections to host www\&.domain\&.org on port 22 then\&.
.IP .IP
.IP "\fB\f(CWsocat - SSL:server:4443,cafile=server\&.crt,cert=client\&.pem\fP\fP"
.IP
is an OpenSSL client that tries to establish a secure connection to an SSL
server\&. Option cafile specifies a file that
contains trust certificates: we trust the server only when it presents one of
these certificates and proofs that it owns the related private key\&.
Otherwise the connection is terminated\&.
With cert a file containing the client certificate
and the associated private key is specified\&. This is required in case the
server wishes a client authentication; many Internet servers do not\&.
.br
The first address (\'-\') can be replaced by almost any other socat address\&.
.IP
.IP "\fB\f(CWsocat SSL-LISTEN:4443,reuseaddr,pf=ip4,fork,cert=server\&.pem,cafile=client\&.crt PIPE\fP\fP"
.IP
is an OpenSSL server that accepts TCP connections, presents the certificate
from the file server\&.pem and forces the client to present a certificate that is
verified against cafile\&.crt\&.
.br
The second address (\'PIPE\') can be replaced by almost any other socat
address\&.
.br
For instructions on generating and distributing OpenSSL keys and certificates
see the additional socat docu \f(CWsocat-openssl\&.txt\fP\&.
.IP
.IP "\fB\f(CWecho |socat -u - file:/tmp/bigfile,create,largefile,seek=100000000000\fP\fP" .IP "\fB\f(CWecho |socat -u - file:/tmp/bigfile,create,largefile,seek=100000000000\fP\fP"
.IP .IP
creates a 100GB sparse file; this requires a file system type that creates a 100GB sparse file; this requires a file system type that
@ -2697,46 +2430,7 @@ to make the squid executable from Cygwin run under Windows, actual per May 2004)
.IP .IP
.IP "\fB\f(CWsocat - tcp:www\&.blackhat\&.org:31337,readbytes=1000\fP\fP" .IP "\fB\f(CWsocat - tcp:www\&.blackhat\&.org:31337,readbytes=1000\fP\fP"
.IP .IP
connects to an unknown service and prevents being flooded\&. connect to an unknown service and prevent being flooded\&.
.IP
.IP "\fB\f(CWsocat -U TCP:target:9999,end-close TCP-L:8888,reuseaddr,fork\fP\fP"
.IP
merges data arriving from different TCP streams on port 8888 to just one stream
to target:9999\&. The end-close option prevents the child
processes forked off by the second address from terminating the shared
connection to 9999 (close(2) just unlinks the inode which stays active as long
as the parent process lives; shutdown(2) would actively terminate the
connection)\&.
.IP
.IP "\fB\f(CWsocat - UDP4-DATAGRAM:192\&.168\&.1\&.0:123,sp=123,broadcast,range=192\&.168\&.1\&.0/24\fP\fP"
.IP
sends a broadcast to the network 192\&.168\&.1\&.0/24 and receives the replies of the
timeservers there\&. Ignores NTP packets from hosts outside this network\&.
.IP
.IP "\fB\f(CWsocat - IP4-DATAGRAM:255\&.255\&.255\&.255:44,broadcast,range=10\&.0\&.0\&.0/8\fP\fP"
.IP
sends a broadcast to the local network(s) using protocol 44\&. Accepts replies
from the private address range only\&.
.IP
.IP "\fB\f(CWsocat - UDP4-DATAGRAM:224\&.255\&.0\&.1:6666,bind=:6666,ip-add-membership=224\&.255\&.0\&.1:eth0\fP\fP"
.IP
transfers data from stdin to the specified multicast address using UDP\&. Both
local and remote ports are 6666\&. Tells the interface eth0 to also accept
multicast packets of the given group\&. Multiple hosts on the local network can
run this command, so all data sent by any of the hosts will be received
by all the other ones\&. Note that there are many possible reasons for failure,
including IP-filters, routing issues, wrong interface selection by the
operating system, bridges, or a badly configured switch\&.
.IP
.IP "\fB\f(CWsocat TCP:host2:4443 TUN:192\&.168\&.255\&.1/24,up\fP\fP"
.IP
establishes one side of a virtual (but not private!) network with host2 where a
similar process might run, with TCP-L and tun address 192\&.168\&.255\&.2\&. They
can reach each other using the addresses 192\&.168\&.255\&.1 and
192\&.168\&.255\&.2\&. Substitute the TCP link with an SSL connection protected by
client and server authentication (see OpenSSL
client and
server)\&.
.IP .IP
.PP .PP
.SH "DIAGNOSTICS" .SH "DIAGNOSTICS"
@ -2843,12 +2537,15 @@ lots of other useful tools and libraries\&.
The \fILinux developers community\fP (http://www\&.linux\&.org/) for providing a free, open source operating The \fILinux developers community\fP (http://www\&.linux\&.org/) for providing a free, open source operating
system\&. system\&.
.PP .PP
\fISourceforge\fP (http://www\&.sourceforge\&.net/) for providing a compile
farm with Solaris, FreeBSD, and MacOS X machines, making these ports possible\&.
.PP
The \fIOpen Group\fP (http://www\&.unix-systems\&.org/) for making their The \fIOpen Group\fP (http://www\&.unix-systems\&.org/) for making their
standard specifications available on the Internet for free\&. standard specifications available on the Internet for free\&.
.PP .PP
.SH "VERSION" .SH "VERSION"
.PP .PP
This man page describes version 1\&.6\&.0 of \fBsocat\fP\&. This man page describes version 1\&.5\&.0 of \fBsocat\fP\&.
.PP .PP
.SH "BUGS" .SH "BUGS"
.PP .PP

File diff suppressed because it is too large Load diff

View file

@ -176,8 +176,8 @@ void msg(int level, const char *format, ...) {
result = gettimeofday(&now, NULL); result = gettimeofday(&now, NULL);
if (result < 0) { if (result < 0) {
/* invoking msg() might create endless recursion; by hand instead */ /* invoking msg() might create endless recursion; by hand instead */
sprintf(buff, "cannot read time: %s["F_pid"] E %s", sprintf(buff, "cannot read time: %s["F_pid".%lu] E %s",
diagopts.progname, getpid(), strerror(errno)); diagopts.progname, getpid(), (unsigned long)pthread_self(), strerror(errno));
_msg(LOG_ERR, buff, strstr(buff, " E "+1)); _msg(LOG_ERR, buff, strstr(buff, " E "+1));
strcpy(buff, "unknown time "); bytes = 20; strcpy(buff, "unknown time "); bytes = 20;
} else { } else {
@ -215,7 +215,8 @@ void msg(int level, const char *format, ...) {
if (diagopts.withhostname) { if (diagopts.withhostname) {
bytes = sprintf(bufp, "%s ", diagopts.hostname), bufp+=bytes; bytes = sprintf(bufp, "%s ", diagopts.hostname), bufp+=bytes;
} }
bytes = sprintf(bufp, "%s["F_pid"] ", diagopts.progname, getpid()); bytes = sprintf(bufp, "%s["F_pid".%lu] ",
diagopts.progname, getpid(), (unsigned long)pthread_self());
bufp += bytes; bufp += bytes;
syslp = bufp; syslp = bufp;
*bufp++ = "DINWEF"[level]; *bufp++ = "DINWEF"[level];

2
ftp.sh
View file

@ -80,7 +80,7 @@ TMPDIR=$(if [ -x /bin/mktemp ]; then
(umask 077; d=/tmp/$USER/FTPSH.$$; mkdir $d; echo $d) (umask 077; d=/tmp/$USER/FTPSH.$$; mkdir $d; echo $d)
fi) fi)
TO="$TMPDIR/to"; FROM="$TMPDIR/from" TO="$TMPDIR/to"; FROM="$TMPDIR/from"
socat $SO1 fifo:$TO,nonblock,ignoreeof!!fifo:$FROM $method:$server:21,$addropts & socat $SO1 fifo:$FROM $method:$server:21,$addropts%fifo:$TO,nonblock,ignoreeof &
S1=$! S1=$!
while ! [ -p "$TO" -a -p "$FROM" ]; do sleep 1; done while ! [ -p "$TO" -a -p "$FROM" ]; do sleep 1; done
exec 4>$TMPDIR/to 3<$TMPDIR/from exec 4>$TMPDIR/to 3<$TMPDIR/from

View file

@ -1,5 +1,5 @@
/* $Id: nestlex.c,v 1.4 2006/06/23 17:04:36 gerhard Exp $ */ /* $Id: nestlex.c,v 1.4 2006/06/23 17:04:36 gerhard Exp $ */
/* Copyright Gerhard Rieger 2006 */ /* Copyright Gerhard Rieger 2006-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* a function for lexical scanning of nested character patterns */ /* a function for lexical scanning of nested character patterns */
@ -29,6 +29,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
const char *squotes[],/* list of strings that quote softly */ const char *squotes[],/* list of strings that quote softly */
const char *nests[],/* list of strings that start nesting; const char *nests[],/* list of strings that start nesting;
every second one is matching end */ every second one is matching end */
bool dropspace, /* drop trailing space before end token */
bool dropquotes, /* drop the outermost quotes */ bool dropquotes, /* drop the outermost quotes */
bool c_esc, /* solve C char escapes: \n \t \0 etc */ bool c_esc, /* solve C char escapes: \n \t \0 etc */
bool html_esc /* solve HTML char escapes: %0d %08 etc */ bool html_esc /* solve HTML char escapes: %0d %08 etc */
@ -38,6 +39,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
const char **quotx; /* loops over quote patterns */ const char **quotx; /* loops over quote patterns */
const char **nestx; /* loops over nest patterns */ const char **nestx; /* loops over nest patterns */
char *out = *token; /* pointer into output token */ char *out = *token; /* pointer into output token */
char *lastnonspace = out;
char c; char c;
int i; int i;
int result; int result;
@ -46,7 +48,9 @@ int nestlex(const char **addr, /* input string; aft points to end token */
/* is this end of input string? */ /* is this end of input string? */
if (*in == 0) { if (*in == 0) {
if (dropspace) {
out = lastnonspace;
}
break; /* end of string */ break; /* end of string */
} }
@ -55,6 +59,9 @@ int nestlex(const char **addr, /* input string; aft points to end token */
while (*endx) { while (*endx) {
if (!strncmp(in, *endx, strlen(*endx))) { if (!strncmp(in, *endx, strlen(*endx))) {
/* this end pattern matches */ /* this end pattern matches */
if (dropspace) {
out = lastnonspace;
}
*addr = in; *addr = in;
*token = out; *token = out;
return 0; return 0;
@ -83,7 +90,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
result = result =
nestlex(&in, &out, len, endnest, NULL/*hquotes*/, nestlex(&in, &out, len, endnest, NULL/*hquotes*/,
NULL/*squotes*/, NULL/*nests*/, NULL/*squotes*/, NULL/*nests*/,
false, c_esc, html_esc); false, false, c_esc, html_esc);
if (result == 0 && dropquotes) { if (result == 0 && dropquotes) {
/* we strip this quote */ /* we strip this quote */
in += strlen(*quotx); in += strlen(*quotx);
@ -101,6 +108,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
} }
if (hquotes && *quotx != NULL) { if (hquotes && *quotx != NULL) {
/* there was a quote; string might continue with hard quote */ /* there was a quote; string might continue with hard quote */
lastnonspace = out;
continue; continue;
} }
@ -126,7 +134,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
result = result =
nestlex(&in, &out, len, endnest, hquotes, nestlex(&in, &out, len, endnest, hquotes,
squotes, nests, squotes, nests,
false, c_esc, html_esc); false, false, c_esc, html_esc);
if (result == 0 && dropquotes) { if (result == 0 && dropquotes) {
/* we strip the trailing quote */ /* we strip the trailing quote */
@ -144,6 +152,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
} }
if (squotes && *quotx != NULL) { if (squotes && *quotx != NULL) {
/* there was a soft quote; string might continue with any quote */ /* there was a soft quote; string might continue with any quote */
lastnonspace = out;
continue; continue;
} }
@ -163,7 +172,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
result = result =
nestlex(&in, &out, len, endnest, hquotes, squotes, nests, nestlex(&in, &out, len, endnest, hquotes, squotes, nests,
false, c_esc, html_esc); false, false, c_esc, html_esc);
if (result == 0) { if (result == 0) {
/* copy endnest */ /* copy endnest */
i = strlen(nestx[1]); while (i > 0) { i = strlen(nestx[1]); while (i > 0) {
@ -182,6 +191,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
} }
if (nests && *nestx) { if (nests && *nestx) {
/* we handled a nested expression, continue loop */ /* we handled a nested expression, continue loop */
lastnonspace = out;
continue; continue;
} }
@ -216,6 +226,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
*token = out; *token = out;
return -1; /* output overflow */ return -1; /* output overflow */
} }
lastnonspace = out;
continue; continue;
} }
@ -227,6 +238,9 @@ int nestlex(const char **addr, /* input string; aft points to end token */
*token = out; *token = out;
return -1; /* output overflow */ return -1; /* output overflow */
} }
if (!isspace(c)) {
lastnonspace = out;
}
} }
/* never come here? */ /* never come here? */
@ -235,3 +249,10 @@ int nestlex(const char **addr, /* input string; aft points to end token */
*token = out; *token = out;
return 0; /* OK */ return 0; /* OK */
} }
int skipsp(const char **text) {
while (isspace(**text)) {
++(*text);
}
return 0;
}

View file

@ -1,5 +1,5 @@
/* $Id: nestlex.h,v 1.3 2006/06/23 17:04:39 gerhard Exp $ */ /* $Id: nestlex.h,v 1.3 2006/06/23 17:04:39 gerhard Exp $ */
/* Copyright Gerhard Rieger 2006 */ /* Copyright Gerhard Rieger 2006-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __nestlex_h_included #ifndef __nestlex_h_included
@ -15,9 +15,13 @@ int nestlex(const char **addr, /* input string; aft points to end token */
const char *squotes[],/* list of strings that quote softly */ const char *squotes[],/* list of strings that quote softly */
const char *nests[],/* list of strings that start nesting; const char *nests[],/* list of strings that start nesting;
every second one is matching end */ every second one is matching end */
bool dropspace, /* drop trailing space before end token */
bool dropquotes, /* drop the outermost quotes */ bool dropquotes, /* drop the outermost quotes */
bool c_esc, /* solve C char escapes: \n \t \0 etc */ bool c_esc, /* solve C char escapes: \n \t \0 etc */
bool html_esc /* solve HTML char escapes: %0d %08 etc */ bool html_esc /* solve HTML char escapes: %0d %08 etc */
); );
extern
int skipsp(const char **text);
#endif /* !defined(__nestlex_h_included) */ #endif /* !defined(__nestlex_h_included) */

View file

@ -1,5 +1,5 @@
/* $Id: procan.c,v 1.17 2006/12/28 07:25:01 gerhard Exp $ */ /* $Id: procan.c,v 1.17 2006/12/28 07:25:01 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* the subroutine procan makes a "PROCess ANalysis". It gathers information /* the subroutine procan makes a "PROCess ANalysis". It gathers information

276
socat.c
View file

@ -20,45 +20,25 @@
#include "filan.h" #include "filan.h"
#include "xio.h" #include "xio.h"
#include "xioopts.h" #include "xioopts.h"
#include "xiosigchld.h"
#include "xiolockfile.h" #include "xiolockfile.h"
#include "xioopen.h"
/* command line options */ /* command line options */
struct { struct {
size_t bufsiz;
bool verbose;
bool verbhex;
struct timeval pollintv; /* with ignoreeof, reread after seconds */
struct timeval closwait; /* after close of x, die after seconds */
struct timeval total_timeout;/* when nothing happens, die after seconds */
bool debug;
bool strictopts; /* stop on errors in address options */ bool strictopts; /* stop on errors in address options */
char logopt; /* y..syslog; s..stderr; f..file; m..mixed */
bool lefttoright; /* first addr ro, second addr wo */
bool righttoleft; /* first addr wo, second addr ro */
xiolock_t lock; /* a lock file */ xiolock_t lock; /* a lock file */
} socat_opts = { } socat_opts = {
8192, /* bufsiz */
false, /* verbose */
false, /* verbhex */
{1,0}, /* pollintv */
{0,500000}, /* closwait */
{0,0}, /* total_timeout */
0, /* debug */
0, /* strictopts */ 0, /* strictopts */
's', /* logopt */
false, /* lefttoright */
false, /* righttoleft */
{ NULL, 0 }, /* lock */ { NULL, 0 }, /* lock */
}; };
void socat_usage(FILE *fd); void socat_usage(FILE *fd);
void socat_version(FILE *fd); void socat_version(FILE *fd);
int socat(const char *address1, const char *address2); int socat(int argc, const char *address1, const char *address2);
int _socat(void); int _socat(xiofile_t *xfd1, xiofile_t *xfd2);
int cv_newline(unsigned char **buff, ssize_t *bytes, int lineterm1, int lineterm2);
void socat_signal(int sig); void socat_signal(int sig);
static int socat_sigchild(struct single *file);
void lftocrlf(char **in, ssize_t *len, size_t bufsiz); void lftocrlf(char **in, ssize_t *len, size_t bufsiz);
void crlftolf(char **in, ssize_t *len, size_t bufsiz); void crlftolf(char **in, ssize_t *len, size_t bufsiz);
@ -93,11 +73,11 @@ int main(int argc, const char *argv[]) {
/* we must init before applying options because env settings have lower /* we must init before applying options because env settings have lower
priority and are to be overridden by options */ priority and are to be overridden by options */
if (xioinitialize() != 0) { if (xioinitialize(XIO_MAYALL) != 0) {
Exit(1); Exit(1);
} }
xiosetopt('p', "!!"); xiosetopt('p', "%");
xiosetopt('o', ":"); xiosetopt('o', ":");
argc0 = argc; /* save for later use */ argc0 = argc; /* save for later use */
@ -114,14 +94,14 @@ int main(int argc, const char *argv[]) {
#endif /* WITH_HELP */ #endif /* WITH_HELP */
case 'd': diag_set('d', NULL); break; case 'd': diag_set('d', NULL); break;
#if WITH_FILAN #if WITH_FILAN
case 'D': socat_opts.debug = true; break; case 'D': xioparams->debug = true; break;
#endif #endif
case 'l': case 'l':
switch (arg1[0][2]) { switch (arg1[0][2]) {
case 'm': /* mixed mode: stderr, then switch to syslog; + facility */ case 'm': /* mixed mode: stderr, then switch to syslog; + facility */
diag_set('s', NULL); diag_set('s', NULL);
xiosetopt('l', "m"); xiosetopt('l', "m");
socat_opts.logopt = arg1[0][2]; xioparams->logopt = arg1[0][2];
xiosetopt('y', &arg1[0][3]); xiosetopt('y', &arg1[0][3]);
break; break;
case 'y': /* syslog + facility */ case 'y': /* syslog + facility */
@ -152,8 +132,8 @@ int main(int argc, const char *argv[]) {
break; break;
} }
break; break;
case 'v': socat_opts.verbose = true; break; case 'v': xioparams->verbose = true; break;
case 'x': socat_opts.verbhex = true; break; case 'x': xioparams->verbhex = true; break;
case 'b': if (arg1[0][2]) { case 'b': if (arg1[0][2]) {
a = *arg1+2; a = *arg1+2;
} else { } else {
@ -163,7 +143,7 @@ int main(int argc, const char *argv[]) {
Exit(1); Exit(1);
} }
} }
socat_opts.bufsiz = strtoul(a, (char **)&a, 0); xioparams->bufsiz = strtoul(a, (char **)&a, 0);
break; break;
case 's': case 's':
diag_set_int('e', E_FATAL); break; diag_set_int('e', E_FATAL); break;
@ -177,9 +157,9 @@ int main(int argc, const char *argv[]) {
} }
} }
rto = strtod(a, (char **)&a); rto = strtod(a, (char **)&a);
socat_opts.closwait.tv_sec = rto; xioparams->closwait.tv_sec = rto;
socat_opts.closwait.tv_usec = xioparams->closwait.tv_usec =
(rto-socat_opts.closwait.tv_sec) * 1000000; (rto-xioparams->closwait.tv_sec) * 1000000;
break; break;
case 'T': if (arg1[0][2]) { case 'T': if (arg1[0][2]) {
a = *arg1+2; a = *arg1+2;
@ -191,12 +171,12 @@ int main(int argc, const char *argv[]) {
} }
} }
rto = strtod(a, (char **)&a); rto = strtod(a, (char **)&a);
socat_opts.total_timeout.tv_sec = rto; xioparams->total_timeout.tv_sec = rto;
socat_opts.total_timeout.tv_usec = xioparams->total_timeout.tv_usec =
(rto-socat_opts.total_timeout.tv_sec) * 1000000; (rto-xioparams->total_timeout.tv_sec) * 1000000;
break; break;
case 'u': socat_opts.lefttoright = true; break; case 'u': xioparams->lefttoright = true; break;
case 'U': socat_opts.righttoleft = true; break; case 'U': xioparams->righttoleft = true; break;
case 'g': xioopts_ignoregroups = true; break; case 'g': xioopts_ignoregroups = true; break;
case 'L': if (socat_opts.lock.lockfile) case 'L': if (socat_opts.lock.lockfile)
Error("only one -L and -W option allowed"); Error("only one -L and -W option allowed");
@ -237,8 +217,9 @@ int main(int argc, const char *argv[]) {
break; break;
#endif /* WITH_IP4 || WITH_IP6 */ #endif /* WITH_IP4 || WITH_IP6 */
case '\0': case '\0':
case '-': /*! this is hardcoded "--" */
case ',': case ',':
case ':': break; /* this "-" is a variation of STDIO */ case ':': break; /* this "-" is a variation of STDIO or -- */
default: default:
xioinqopt('p', buff, sizeof(buff)); xioinqopt('p', buff, sizeof(buff));
if (arg1[0][1] == buff[0]) { if (arg1[0][1] == buff[0]) {
@ -251,15 +232,20 @@ int main(int argc, const char *argv[]) {
xioinqopt('p', buff, sizeof(buff)); xioinqopt('p', buff, sizeof(buff));
if (arg1[0][0] == '-' && if (arg1[0][0] == '-' &&
(arg1[0][1] == '\0' || arg1[0][1] == ':' || (arg1[0][1] == '\0' || arg1[0][1] == ':' ||
arg1[0][1] == ',' || arg1[0][1] == buff[0])) arg1[0][1] == ',' || arg1[0][1] == '-'/*!*/ ||
arg1[0][1] == buff[0]))
break; break;
++arg1; --argc; ++arg1; --argc;
} }
#if 0
Info1("%d address arguments", argc);
#else
if (argc != 2) { if (argc != 2) {
Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc); Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc);
Exit(1); Exit(1);
} }
if (socat_opts.lefttoright && socat_opts.righttoleft) { #endif
if (xioparams->lefttoright && xioparams->righttoleft) {
Error("-U and -u must not be combined"); Error("-U and -u must not be combined");
} }
@ -291,6 +277,26 @@ int main(int argc, const char *argv[]) {
Signal(SIGFPE, socat_signal); Signal(SIGFPE, socat_signal);
Signal(SIGSEGV, socat_signal); Signal(SIGSEGV, socat_signal);
Signal(SIGTERM, socat_signal); Signal(SIGTERM, socat_signal);
#if HAVE_SIGACTION
{
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_NOCLDSTOP|SA_RESTART|SA_SIGINFO
#ifdef SA_NOMASK
|SA_NOMASK
#endif
;
act.sa_sigaction = xiosigaction_subaddr_ok;
if (Sigaction(SIGUSR1, &act, NULL) < 0) {
/*! Linux man does not explicitely say that errno is defined */
Warn1("sigaction(SIGUSR1, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno));
}
}
#else /* !HAVE_SIGACTION */
if (Signal(SIGUSR1, xiosigaction_subaddr_ok) == SIG_ERR) {
Warn1("signal(SIGCHLD, xiosigaction_subaddr_ok): %s", strerror(errno));
}
#endif /* !HAVE_SIGACTION */
/* set xio hooks */ /* set xio hooks */
xiohook_newchild = &socat_newchild; xiohook_newchild = &socat_newchild;
@ -304,7 +310,7 @@ int main(int argc, const char *argv[]) {
Atexit(socat_unlock); Atexit(socat_unlock);
result = socat(arg1[0], arg1[1]); result = socat(argc, arg1[0], arg1[1]);
Notice1("exiting with status %d", result); Notice1("exiting with status %d", result);
Exit(result); Exit(result);
return 0; /* not reached, just for gcc -Wall */ return 0; /* not reached, just for gcc -Wall */
@ -516,125 +522,75 @@ void socat_version(FILE *fd) {
} }
xiofile_t *sock1, *sock2;
int closing = 0; /* 0..no eof yet, 1..first eof just occurred,
2..counting down closing timeout */
/* call this function when the common command line options are parsed, and the /* call this function when the common command line options are parsed, and the
addresses are extracted (but not resolved). */ addresses are extracted (but not resolved). */
int socat(const char *address1, const char *address2) { int socat(int argc, const char *address1, const char *address2) {
int mayexec; xiofile_t *xfd1, *xfd2;
xioinitialize(XIO_MAYALL);
#if 1 #if 1
if (Signal(SIGPIPE, SIG_IGN) == SIG_ERR) { if (Signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
Warn1("signal(SIGPIPE, SIG_IGN): %s", strerror(errno)); Warn1("signal(SIGPIPE, SIG_IGN): %s", strerror(errno));
} }
#endif #endif
if (socat_opts.lefttoright) { /* open the first (left most) address */
if ((sock1 = xioopen(address1, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) { if (xioparams->lefttoright) {
if ((xfd1 = socat_open(address1, XIO_RDONLY, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
return -1; return -1;
} }
xiosetsigchild(sock1, socat_sigchild); } else if (xioparams->righttoleft) {
} else if (socat_opts.righttoleft) { if ((xfd1 = socat_open(address1, XIO_WRONLY, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
if ((sock1 = xioopen(address1, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
return -1; return -1;
} }
xiosetsigchild(sock1, socat_sigchild);
} else { } else {
if ((sock1 = xioopen(address1, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) { if ((xfd1 = socat_open(address1, XIO_RDWR, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
return -1; return -1;
} }
xiosetsigchild(sock1, socat_sigchild);
} }
xiosetsigchild(xfd1, socat_sigchild);
#if 1 /*! */ #if 1 /*! */
if (XIO_READABLE(sock1) && if (XIO_RDSTREAM(xfd1)->subaddrstat < 0) {
(XIO_RDSTREAM(sock1)->howtoend == END_KILL || Info1("child "F_pid" has already died",
XIO_RDSTREAM(sock1)->howtoend == END_CLOSE_KILL || XIO_RDSTREAM(xfd1)->child.pid);
XIO_RDSTREAM(sock1)->howtoend == END_SHUTDOWN_KILL)) { XIO_RDSTREAM(xfd1)->child.pid = 0;
if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown1) {
/* child has alread died... but it might have put regular data into
the communication channel, so continue */
Info1("child "F_pid" has already died (diedunknown1)",
XIO_RDSTREAM(sock1)->para.exec.pid);
diedunknown1 = 0;
XIO_RDSTREAM(sock1)->para.exec.pid = 0;
/* return STAT_RETRYLATER; */ /* return STAT_RETRYLATER; */
} else if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown2) {
Info1("child "F_pid" has already died (diedunknown2)",
XIO_RDSTREAM(sock1)->para.exec.pid);
diedunknown2 = 0;
XIO_RDSTREAM(sock1)->para.exec.pid = 0;
} else if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown3) {
Info1("child "F_pid" has already died (diedunknown3)",
XIO_RDSTREAM(sock1)->para.exec.pid);
diedunknown3 = 0;
XIO_RDSTREAM(sock1)->para.exec.pid = 0;
} else if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown4) {
Info1("child "F_pid" has already died (diedunknown4)",
XIO_RDSTREAM(sock1)->para.exec.pid);
diedunknown4 = 0;
XIO_RDSTREAM(sock1)->para.exec.pid = 0;
}
} }
#endif #endif
mayexec = (sock1->common.flags&XIO_DOESCONVERT ? 0 : XIO_MAYEXEC); /* second (right) addresses chain */
if (XIO_WRITABLE(sock1)) { if (XIO_WRITABLE(xfd1)) {
if (XIO_READABLE(sock1)) { if (XIO_READABLE(xfd1)) {
if ((sock2 = xioopen(address2, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) { if ((xfd2 = socat_open(address2, XIO_RDWR, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYEXEC|XIO_MAYCONVERT)) == NULL) {
return -1; return -1;
} }
xiosetsigchild(sock2, socat_sigchild);
} else { } else {
if ((sock2 = xioopen(address2, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) { if ((xfd2 = socat_open(address2, XIO_RDONLY, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYEXEC|XIO_MAYCONVERT)) == NULL) {
return -1; return -1;
} }
xiosetsigchild(sock2, socat_sigchild);
} }
} else { /* assuming sock1 is readable */ } else { /* assuming sock1 is readable */
if ((sock2 = xioopen(address2, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) { if ((xfd2 = socat_open(address2, XIO_WRONLY, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYEXEC|XIO_MAYCONVERT)) == NULL) {
return -1; return -1;
} }
xiosetsigchild(sock2, socat_sigchild);
} }
xiosetsigchild(xfd2, socat_sigchild);
#if 1 /*! */ #if 1 /*! */
if (XIO_READABLE(sock2) && if (XIO_RDSTREAM(xfd2)->subaddrstat < 0) {
(XIO_RDSTREAM(sock2)->howtoend == END_KILL || Info1("child "F_pid" has already died",
XIO_RDSTREAM(sock2)->howtoend == END_CLOSE_KILL || XIO_RDSTREAM(xfd2)->child.pid);
XIO_RDSTREAM(sock2)->howtoend == END_SHUTDOWN_KILL)) { XIO_RDSTREAM(xfd2)->child.pid = 0;
if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown1) {
/* child has alread died... but it might have put regular data into
the communication channel, so continue */
Info1("child "F_pid" has already died (diedunknown1)",
XIO_RDSTREAM(sock2)->para.exec.pid);
diedunknown1 = 0;
XIO_RDSTREAM(sock2)->para.exec.pid = 0;
/* return STAT_RETRYLATER; */ /* return STAT_RETRYLATER; */
} else if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown2) {
Info1("child "F_pid" has already died (diedunknown2)",
XIO_RDSTREAM(sock2)->para.exec.pid);
diedunknown2 = 0;
XIO_RDSTREAM(sock2)->para.exec.pid = 0;
} else if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown3) {
Info1("child "F_pid" has already died (diedunknown3)",
XIO_RDSTREAM(sock2)->para.exec.pid);
diedunknown3 = 0;
XIO_RDSTREAM(sock2)->para.exec.pid = 0;
} else if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown4) {
Info1("child "F_pid" has already died (diedunknown4)",
XIO_RDSTREAM(sock2)->para.exec.pid);
diedunknown4 = 0;
XIO_RDSTREAM(sock2)->para.exec.pid = 0;
}
} }
#endif #endif
Info("resolved and opened all sock addresses"); Info("resolved and opened all sock addresses");
return return
_socat(); /* nsocks, sockets are visible outside function */ _socat(xfd1, xfd2);
} }
#if 0
/* checks if this is a connection to a child process, and if so, sees if the /* checks if this is a connection to a child process, and if so, sees if the
child already died, leaving some data for us. child already died, leaving some data for us.
returns <0 if an error occurred; returns <0 if an error occurred;
@ -646,10 +602,10 @@ int childleftdata(xiofile_t *xfd) {
int retval; int retval;
/* have to check if a child process died before, but left read data */ /* have to check if a child process died before, but left read data */
if (XIO_READABLE(xfd) && if (XIO_READABLE(xfd) &&
(XIO_RDSTREAM(xfd)->howtoend == END_KILL || (/*0 XIO_RDSTREAM(xfd)->howtoclose == END_KILL ||*/
XIO_RDSTREAM(xfd)->howtoend == END_CLOSE_KILL || XIO_RDSTREAM(xfd)->howtoclose == END_CLOSE_KILL ||
XIO_RDSTREAM(xfd)->howtoend == END_SHUTDOWN_KILL) && XIO_RDSTREAM(xfd)->howtoclose == END_SHUTDOWN_KILL) &&
XIO_RDSTREAM(xfd)->para.exec.pid == 0) { XIO_RDSTREAM(xfd)->child.pid == 0) {
struct timeval time0 = { 0,0 }; struct timeval time0 = { 0,0 };
FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt); FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt);
@ -658,17 +614,17 @@ int childleftdata(xiofile_t *xfd) {
/*0 FD_SET(XIO_GETRDFD(xfd), &expt);*/ /*0 FD_SET(XIO_GETRDFD(xfd), &expt);*/
} }
do { do {
retval = Select(FOPEN_MAX, &in, &out, &expt, &time0); retval = Select(FD_SETSIZE, &in, &out, &expt, &time0);
} while (retval < 0 && errno == EINTR); } while (retval < 0 && errno == EINTR);
if (retval < 0) { if (retval < 0) {
#if HAVE_FDS_BITS #if HAVE_FDS_BITS
Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s", Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s",
FOPEN_MAX, in.fds_bits[0], out.fds_bits[0], FD_SETSIZE, in.fds_bits[0], out.fds_bits[0],
expt.fds_bits[0], strerror(errno)); expt.fds_bits[0], strerror(errno));
#else #else
Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s", Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s",
FOPEN_MAX, in.__fds_bits[0], out.__fds_bits[0], FD_SETSIZE, in.__fds_bits[0], out.__fds_bits[0],
expt.__fds_bits[0], strerror(errno)); expt.__fds_bits[0], strerror(errno));
#endif #endif
return -1; return -1;
@ -681,9 +637,9 @@ int childleftdata(xiofile_t *xfd) {
} }
return 0; return 0;
} }
#endif /* 0 */
int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe, #if 0
unsigned char **buff, size_t bufsiz, bool righttoleft);
bool mayrd1; /* sock1 has read data or eof, according to select() */ bool mayrd1; /* sock1 has read data or eof, according to select() */
bool mayrd2; /* sock2 has read data or eof, according to select() */ bool mayrd2; /* sock2 has read data or eof, according to select() */
@ -693,7 +649,7 @@ bool maywr2; /* sock2 can be written to, according to select() */
/* here we come when the sockets are opened (in the meaning of C language), /* here we come when the sockets are opened (in the meaning of C language),
and their options are set/applied and their options are set/applied
returns -1 on error or 0 on success */ returns -1 on error or 0 on success */
int _socat(void) { int _socat(xiofile_t *xfd1, xiofile_t *xfd2) {
fd_set in, out, expt; fd_set in, out, expt;
int retval; int retval;
unsigned char *buff; unsigned char *buff;
@ -702,6 +658,9 @@ int _socat(void) {
int wasaction = 1; /* last select was active, do NOT sleep before next */ int wasaction = 1; /* last select was active, do NOT sleep before next */
struct timeval total_timeout; /* the actual total timeout timer */ struct timeval total_timeout; /* the actual total timeout timer */
sock1 = xfd1;
sock2 = xfd2;
#if WITH_FILAN #if WITH_FILAN
if (socat_opts.debug) { if (socat_opts.debug) {
int fdi, fdo; int fdi, fdo;
@ -732,7 +691,7 @@ int _socat(void) {
#endif /* WITH_FILAN */ #endif /* WITH_FILAN */
/* when converting nl to crnl, size might double */ /* when converting nl to crnl, size might double */
buff = Malloc(2*socat_opts.bufsiz+1); buff = Malloc(2*xioparams->bufsiz+1);
if (buff == NULL) return -1; if (buff == NULL) return -1;
if (socat_opts.logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') { if (socat_opts.logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') {
@ -818,6 +777,7 @@ int _socat(void) {
if (XIO_READABLE(sock1) && if (XIO_READABLE(sock1) &&
!(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof) && !(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof) &&
!socat_opts.righttoleft) { !socat_opts.righttoleft) {
Debug3("*** sock1: %p [%d,%d]", sock1, XIO_GETRDFD(sock1), XIO_GETWRFD(sock1));
if (!mayrd1) { if (!mayrd1) {
FD_SET(XIO_GETRDFD(sock1), &in); FD_SET(XIO_GETRDFD(sock1), &in);
} }
@ -828,6 +788,7 @@ int _socat(void) {
if (XIO_READABLE(sock2) && if (XIO_READABLE(sock2) &&
!(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof) && !(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof) &&
!socat_opts.lefttoright) { !socat_opts.lefttoright) {
Debug3("*** sock2: %p [%d,%d]", sock2, XIO_GETRDFD(sock2), XIO_GETWRFD(sock2));
if (!mayrd2) { if (!mayrd2) {
FD_SET(XIO_GETRDFD(sock2), &in); FD_SET(XIO_GETRDFD(sock2), &in);
} }
@ -835,7 +796,7 @@ int _socat(void) {
FD_SET(XIO_GETWRFD(sock1), &out); FD_SET(XIO_GETWRFD(sock1), &out);
} }
} }
retval = Select(FOPEN_MAX, &in, &out, &expt, to); retval = Select(FD_SETSIZE, &in, &out, &expt, to);
_errno = errno; _errno = errno;
if (retval < 0 && errno == EINTR) { if (retval < 0 && errno == EINTR) {
Info1("select(): %s", strerror(errno)); Info1("select(): %s", strerror(errno));
@ -851,12 +812,12 @@ int _socat(void) {
if (retval < 0) { if (retval < 0) {
#if HAVE_FDS_BITS #if HAVE_FDS_BITS
Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s", Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s",
FOPEN_MAX, in.fds_bits[0], out.fds_bits[0], FD_SETSIZE, in.fds_bits[0], out.fds_bits[0],
expt.fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0, expt.fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0,
strerror(errno)); strerror(errno));
#else #else
Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s", Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s",
FOPEN_MAX, in.__fds_bits[0], out.__fds_bits[0], FD_SETSIZE, in.__fds_bits[0], out.__fds_bits[0],
expt.__fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0, expt.__fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0,
strerror(errno)); strerror(errno));
#endif #endif
@ -900,7 +861,7 @@ int _socat(void) {
if (mayrd1 && maywr2) { if (mayrd1 && maywr2) {
mayrd1 = false; mayrd1 = false;
if ((bytes1 = xiotransfer(sock1, sock2, &buff, socat_opts.bufsiz, false)) if ((bytes1 = xiotransfer(sock1, sock2, &buff, xioparams->bufsiz, false))
< 0) { < 0) {
if (errno != EAGAIN) { if (errno != EAGAIN) {
closing = MAX(closing, 1); closing = MAX(closing, 1);
@ -920,15 +881,22 @@ int _socat(void) {
/* avoid idle when all readbytes already there */ /* avoid idle when all readbytes already there */
mayrd1 = true; mayrd1 = true;
} }
} else { /* bytes2 == 0 */
if (XIO_RDSTREAM(sock1)->ignoreeof && !closing) {
;
} else {
XIO_RDSTREAM(sock1)->eof = 2;
closing = MAX(closing, 1);
} }
/* (bytes1 == 0) handled later */ /* (bytes1 == 0) handled later */
}
} else { } else {
bytes1 = -1; bytes1 = -1;
} }
if (mayrd2 && maywr1) { if (mayrd2 && maywr1) {
mayrd2 = false; mayrd2 = false;
if ((bytes2 = xiotransfer(sock2, sock1, &buff, socat_opts.bufsiz, true)) if ((bytes2 = xiotransfer(sock2, sock1, &buff, xioparams->bufsiz, true))
< 0) { < 0) {
if (errno != EAGAIN) { if (errno != EAGAIN) {
closing = MAX(closing, 1); closing = MAX(closing, 1);
@ -948,8 +916,15 @@ int _socat(void) {
/* avoid idle when all readbytes already there */ /* avoid idle when all readbytes already there */
mayrd2 = true; mayrd2 = true;
} }
} else { /* bytes == 0 */
if (XIO_RDSTREAM(sock2)->ignoreeof && !closing) {
;
} else {
XIO_RDSTREAM(sock2)->eof = 2;
closing = MAX(closing, 1);
} }
/* (bytes2 == 0) handled later */ /* (bytes2 == 0) handled later */
}
} else { } else {
bytes2 = -1; bytes2 = -1;
} }
@ -959,7 +934,7 @@ int _socat(void) {
if (bytes1 == 0 || XIO_RDSTREAM(sock1)->eof >= 2) { if (bytes1 == 0 || XIO_RDSTREAM(sock1)->eof >= 2) {
if (XIO_RDSTREAM(sock1)->ignoreeof && !closing) { if (XIO_RDSTREAM(sock1)->ignoreeof && !closing) {
Debug1("socket 1 (fd %d) is at EOF, ignoring", Debug1("socket 1 (fd %d) is at EOF, ignoring",
XIO_RDSTREAM(sock1)->fd); /*! */ XIO_RDSTREAM(sock1)->fd1); /*! */
polling = 1; polling = 1;
} else { } else {
Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1)); Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1));
@ -973,7 +948,7 @@ int _socat(void) {
if (bytes2 == 0 || XIO_RDSTREAM(sock2)->eof >= 2) { if (bytes2 == 0 || XIO_RDSTREAM(sock2)->eof >= 2) {
if (XIO_RDSTREAM(sock2)->ignoreeof && !closing) { if (XIO_RDSTREAM(sock2)->ignoreeof && !closing) {
Debug1("socket 2 (fd %d) is at EOF, ignoring", Debug1("socket 2 (fd %d) is at EOF, ignoring",
XIO_RDSTREAM(sock2)->fd); XIO_RDSTREAM(sock2)->fd1);
polling = 1; polling = 1;
} else { } else {
Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2)); Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2));
@ -991,8 +966,9 @@ int _socat(void) {
return 0; return 0;
} }
#endif /* 0 */
#if 0
#define MAXTIMESTAMPLEN 128 #define MAXTIMESTAMPLEN 128
/* prints the timestamp to the buffer and terminates it with '\0'. This buffer /* prints the timestamp to the buffer and terminates it with '\0'. This buffer
should be at least MAXTIMESTAMPLEN bytes long. should be at least MAXTIMESTAMPLEN bytes long.
@ -1035,7 +1011,9 @@ int gettimestamp(char *timestamp) {
#endif /* !HAVE_GETTIMEOFDAY */ #endif /* !HAVE_GETTIMEOFDAY */
return 0; return 0;
} }
#endif
#if 0
static const char *prefixltor = "> "; static const char *prefixltor = "> ";
static const char *prefixrtol = "< "; static const char *prefixrtol = "< ";
static unsigned long numltor; static unsigned long numltor;
@ -1061,8 +1039,9 @@ static int
fputs(buff, file); fputs(buff, file);
return 0; return 0;
} }
#endif /* 0 */
#if 0
/* inpipe is suspected to have read data available; read at most bufsiz bytes /* inpipe is suspected to have read data available; read at most bufsiz bytes
and transfer them to outpipe. Perform required data conversions. and transfer them to outpipe. Perform required data conversions.
buff should be at least twice as large as bufsiz, to allow all standard buff should be at least twice as large as bufsiz, to allow all standard
@ -1078,7 +1057,7 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
unsigned char **buff, size_t bufsiz, bool righttoleft) { unsigned char **buff, size_t bufsiz, bool righttoleft) {
ssize_t bytes, writt; ssize_t bytes, writt;
bytes = xioread(inpipe, *buff, socat_opts.bufsiz); bytes = xioread(inpipe, *buff, xioparams->bufsiz);
if (bytes < 0) { if (bytes < 0) {
if (errno != EAGAIN) if (errno != EAGAIN)
XIO_RDSTREAM(inpipe)->eof = 2; XIO_RDSTREAM(inpipe)->eof = 2;
@ -1105,7 +1084,7 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
errno = EAGAIN; return -1; errno = EAGAIN; return -1;
} }
if (socat_opts.verbose && socat_opts.verbhex) { if (xioparams->verbose && xioparams->verbhex) {
/* Hack-o-rama */ /* Hack-o-rama */
size_t i = 0; size_t i = 0;
size_t j; size_t j;
@ -1178,7 +1157,7 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
} }
++i; ++i;
} }
} else if (socat_opts.verbhex) { } else if (xioparams->verbhex) {
int i; int i;
/*! prefix? */ /*! prefix? */
for (i = 0; i < bytes; ++i) { for (i = 0; i < bytes; ++i) {
@ -1206,11 +1185,13 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
} }
return writt; return writt;
} }
#endif /* 0 */
#if 0
#define CR '\r' #define CR '\r'
#define LF '\n' #define LF '\n'
int cv_newline(unsigned char **buff, ssize_t *bytes, int cv_newline(unsigned char **buff, ssize_t *bytes,
int lineterm1, int lineterm2) { int lineterm1, int lineterm2) {
/* must perform newline changes */ /* must perform newline changes */
@ -1260,7 +1241,7 @@ int cv_newline(unsigned char **buff, ssize_t *bytes,
} else { } else {
from = '\r'; from = '\r';
} }
if ((buf2 = Malloc(2*socat_opts.bufsiz+1)) == NULL) { if ((buf2 = Malloc(2*xioparams->bufsiz+1)) == NULL) {
return -1; return -1;
} }
s = *buff; t = buf2; z = *buff + *bytes; s = *buff; t = buf2; z = *buff + *bytes;
@ -1279,6 +1260,7 @@ int cv_newline(unsigned char **buff, ssize_t *bytes,
} }
return 0; return 0;
} }
#endif /* 0 */
void socat_signal(int signum) { void socat_signal(int signum) {
switch (signum) { switch (signum) {
@ -1302,6 +1284,7 @@ void socat_signal(int signum) {
Exit(128+signum); Exit(128+signum);
} }
#if 0
/* this is the callback when the child of an address died */ /* this is the callback when the child of an address died */
static int socat_sigchild(struct single *file) { static int socat_sigchild(struct single *file) {
if (file->ignoreeof && !closing) { if (file->ignoreeof && !closing) {
@ -1312,6 +1295,7 @@ static int socat_sigchild(struct single *file) {
} }
return 0; return 0;
} }
#endif
static int socat_lock(void) { static int socat_lock(void) {
int lockrc; int lockrc;

View file

@ -197,6 +197,22 @@ int sycSSL_set_fd(SSL *ssl, int fd) {
return result; return result;
} }
int sycSSL_set_rfd(SSL *ssl, int fd) {
int result;
Debug2("SSL_set_rfd(%p, %d)", ssl, fd);
result = SSL_set_rfd(ssl, fd);
Debug1("SSL_set_rfd() -> %d", result);
return result;
}
int sycSSL_set_wfd(SSL *ssl, int fd) {
int result;
Debug2("SSL_set_wfd(%p, %d)", ssl, fd);
result = SSL_set_wfd(ssl, fd);
Debug1("SSL_set_wfd() -> %d", result);
return result;
}
int sycSSL_connect(SSL *ssl) { int sycSSL_connect(SSL *ssl) {
int result; int result;
Debug1("SSL_connect(%p)", ssl); Debug1("SSL_connect(%p)", ssl);

View file

@ -32,6 +32,8 @@ int sycSSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str);
int sycSSL_set_cipher_list(SSL *ssl, const char *str); int sycSSL_set_cipher_list(SSL *ssl, const char *str);
long sycSSL_get_verify_result(SSL *ssl); long sycSSL_get_verify_result(SSL *ssl);
int sycSSL_set_fd(SSL *ssl, int fd); int sycSSL_set_fd(SSL *ssl, int fd);
int sycSSL_set_rfd(SSL *ssl, int fd);
int sycSSL_set_wfd(SSL *ssl, int fd);
int sycSSL_connect(SSL *ssl); int sycSSL_connect(SSL *ssl);
int sycSSL_accept(SSL *ssl); int sycSSL_accept(SSL *ssl);
int sycSSL_read(SSL *ssl, void *buf, int num); int sycSSL_read(SSL *ssl, void *buf, int num);
@ -77,6 +79,8 @@ int sycFIPS_mode_set(int onoff);
#define sycSSL_set_cipher_list(s,t) SSL_set_cipher_list(s,t) #define sycSSL_set_cipher_list(s,t) SSL_set_cipher_list(s,t)
#define sycSSL_get_verify_result(s) SSL_get_verify_result(s) #define sycSSL_get_verify_result(s) SSL_get_verify_result(s)
#define sycSSL_set_fd(s,f) SSL_set_fd(s,f) #define sycSSL_set_fd(s,f) SSL_set_fd(s,f)
#define sycSSL_set_rfd(s,f) SSL_set_rfd(s,f)
#define sycSSL_set_wfd(s,f) SSL_set_wfd(s,f)
#define sycSSL_connect(s) SSL_connect(s) #define sycSSL_connect(s) SSL_connect(s)
#define sycSSL_accept(s) SSL_accept(s) #define sycSSL_accept(s) SSL_accept(s)
#define sycSSL_read(s,b,n) SSL_read(s,b,n) #define sycSSL_read(s,b,n) SSL_read(s,b,n)

111
sycls.c
View file

@ -720,6 +720,41 @@ int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
return result; return result;
} }
/* we only show the first word of the fd_set's; hope this is enough for most
cases. */
int Pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timespec *timeout, const sigset_t *sigmask) {
int result, _errno;
#if HAVE_FDS_BITS
Debug8("pselect(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu.%06u, {0x%lx})",
n, readfds->fds_bits[0], writefds->fds_bits[0],
exceptfds->fds_bits[0],
timeout?"&":"NULL/", timeout?timeout->tv_sec:0,
timeout?timeout->tv_nsec:0, /*sigmask->__val[0]*/
*(unsigned long *)sigmask);
#else
Debug8("pselect(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu.%06u, {0x%lx})",
n, readfds->__fds_bits[0], writefds->__fds_bits[0],
exceptfds->__fds_bits[0],
timeout?"&":"NULL/", timeout?timeout->tv_sec:0,
timeout?timeout->tv_nsec:0, *(unsigned long *)sigmask);
#endif
result = pselect(n, readfds, writefds, exceptfds, timeout, sigmask);
_errno = errno;
#if HAVE_FDS_BITS
Debug4("pselect -> (, 0x%lx, 0x%lx, 0x%lx, , ), %d",
readfds->fds_bits[0], writefds->fds_bits[0], exceptfds->fds_bits[0],
result);
#else
Debug4("pselect -> (, 0x%lx, 0x%lx, 0x%lx, , ), %d",
readfds->__fds_bits[0], writefds->__fds_bits[0],
exceptfds->__fds_bits[0],
result);
#endif
errno = _errno;
return result;
}
pid_t Fork(void) { pid_t Fork(void) {
pid_t pid; pid_t pid;
int _errno; int _errno;
@ -764,12 +799,15 @@ int Sigaction(int signum, const struct sigaction *act,
} }
#endif /* HAVE_SIGACTION */ #endif /* HAVE_SIGACTION */
int Sigprocmask(int how, const sigset_t *set, sigset_t *oset) { int Sigprocmask(int how, const sigset_t *set, sigset_t *oldset) {
int retval; int _errno, result;
Debug3("sigprocmask(%d, %p, %p)", how, set, oset); Debug3("sigprocmask(%d, {0x%lx}, %p)", how, *(unsigned long *)set, oldset);
retval = sigprocmask(how, set, oset); result = sigprocmask(how, set, oldset);
Debug1("sigprocmask() -> %d", retval); _errno = errno;
return retval; Debug4("sigprocmask(,,%s%lu%s) -> %d",
oldset?" {0x":"", oldset?*(unsigned long *)oldset:0, oldset?"}":"", result);
errno = _errno;
return result;
} }
unsigned int Alarm(unsigned int seconds) { unsigned int Alarm(unsigned int seconds) {
@ -1138,7 +1176,7 @@ int Pause(void) {
return retval; return retval;
} }
#if WITH_IP4 || WITH_IP6 #if _WITH_IP4 || _WITH_IP6
struct hostent *Gethostbyname(const char *name) { struct hostent *Gethostbyname(const char *name) {
struct hostent *hent; struct hostent *hent;
Debug1("gethostbyname(\"%s\")", name); Debug1("gethostbyname(\"%s\")", name);
@ -1154,7 +1192,7 @@ struct hostent *Gethostbyname(const char *name) {
} }
return hent; return hent;
} }
#endif /* WITH_IP4 || WITH_IP6 */ #endif /* _WITH_IP4 || _WITH_IP6 */
#if (_WITH_IP4 || _WITH_IP6) && HAVE_GETADDRINFO #if (_WITH_IP4 || _WITH_IP6) && HAVE_GETADDRINFO
int Getaddrinfo(const char *node, const char *service, int Getaddrinfo(const char *node, const char *service,
@ -1397,6 +1435,27 @@ void Abort(void) {
abort(); abort();
} }
int Pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg) {
int result, _errno;
Debug4("pthread_create(%p, %p, %p, %p)", thread, attr, start_routine, arg);
result = pthread_create(thread, attr, start_routine, arg);
_errno = errno;
Debug1("pthread_create() -> %d", errno);
errno = _errno;
return result;
}
int Pthread_join(pthread_t thread, void **value_ptr) {
int result, _errno;
Debug2("pthread_join(%p, %p)", thread, value_ptr);
result = pthread_join(thread, value_ptr);
_errno = errno;
Debug1("pthread_join() -> %d", errno);
errno = _errno;
return result;
}
int Mkstemp(char *template) { int Mkstemp(char *template) {
int result, _errno; int result, _errno;
Debug1("mkstemp(\"%s\")", template); Debug1("mkstemp(\"%s\")", template);
@ -1500,4 +1559,40 @@ void Add_history(const char *string) {
#endif /* WITH_READLINE */ #endif /* WITH_READLINE */
#if WITH_GZIP
gzFile Gzdopen(int fd, const char *mode) {
gzFile result;
Debug2("gzdopen(%d, \"%s\")", fd, mode);
result = gzdopen(fd, mode);
Debug1("gzdopen() -> %p", result);
return result;
}
int Gzread(gzFile file, voidp buf, unsigned len) {
int result;
Debug3("gzread(%p, %p, %u)", file, buf, len);
result = gzread(file, buf, len);
Debug1("gzread() -> %d", result);
return result;
}
int Gzwrite(gzFile file, const voidp buf, unsigned len) {
int result;
Debug3("gzwrite(%p, %p, %u)", file, buf, len);
result = gzwrite(file, buf, len);
Debug1("gzwrite() -> %d", result);
return result;
}
int Gzclose(gzFile file) {
int result;
Debug1("gzclose(%p)", file);
result = gzclose(file);
Debug1("gzclose() -> %d", result);
return result;
}
#endif /* WITH_GZIP */
#endif /* WITH_SYCLS */ #endif /* WITH_SYCLS */

21
sycls.h
View file

@ -75,6 +75,8 @@ int Chmod(const char *path, mode_t mode);
int Poll(struct pollfd *ufds, unsigned int nfds, int timeout); int Poll(struct pollfd *ufds, unsigned int nfds, int timeout);
int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout); struct timeval *timeout);
int Pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timespec *timeout, const sigset_t *sigmask);
pid_t Fork(void); pid_t Fork(void);
pid_t Waitpid(pid_t pid, int *status, int options); pid_t Waitpid(pid_t pid, int *status, int options);
#ifndef HAVE_TYPE_SIGHANDLER #ifndef HAVE_TYPE_SIGHANDLER
@ -133,9 +135,13 @@ int Grantpt(int fd);
int Unlockpt(int fd); int Unlockpt(int fd);
int Gethostname(char *name, size_t len); int Gethostname(char *name, size_t len);
int Uname(struct utsname *buf); int Uname(struct utsname *buf);
int Sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
int Atexit(void (*func)(void)); int Atexit(void (*func)(void));
void Exit(int status); void Exit(int status);
void Abort(void); void Abort(void);
int Pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
int Pthread_join(pthread_t thread, void **value_ptr);
int Mkstemp(char *template); int Mkstemp(char *template);
char *Readline(const char *prompt); char *Readline(const char *prompt);
@ -145,6 +151,12 @@ int Write_history(const char *filename);
int Append_history(int nelements, const char *filename); int Append_history(int nelements, const char *filename);
int Read_history(const char *filename); int Read_history(const char *filename);
void Add_history(const char *string); void Add_history(const char *string);
#if WITH_GZIP
gzFile Gzdopen(int fd, const char *mode) {
int Gzread(gzFile file, voidp buf, unsigned len) {
int Gzwrite(gzFile file, const voidp buf, unsigned len) {
int Gzclose(gzFile file) {
#endif /* WITH_GZIP */
#else /* !WITH_SYCLS */ #else /* !WITH_SYCLS */
@ -205,6 +217,7 @@ void Add_history(const char *string);
#define Chmod(p,m) chmod(p,m) #define Chmod(p,m) chmod(p,m)
#define Poll(u, n, t) poll(u, n, t) #define Poll(u, n, t) poll(u, n, t)
#define Select(n,r,w,e,t) select(n,r,w,e,t) #define Select(n,r,w,e,t) select(n,r,w,e,t)
#define Pselect(n,r,w,e,t,s) select(n,r,w,e,t,s)
#define Fork() fork() #define Fork() fork()
#define Waitpid(p,s,o) waitpid(p,s,o) #define Waitpid(p,s,o) waitpid(p,s,o)
#define Signal(s,h) signal(s,h) #define Signal(s,h) signal(s,h)
@ -252,9 +265,12 @@ void Add_history(const char *string);
#define Getpgid(p) getpgid(p) #define Getpgid(p) getpgid(p)
#define Gethostname(n,l) gethostname(n,l) #define Gethostname(n,l) gethostname(n,l)
#define Uname(b) uname(b) #define Uname(b) uname(b)
#define Sigprocmask(h,s,o) sigprocmask(h,s,o)
#define Atexit(f) atexit(f) #define Atexit(f) atexit(f)
#define Exit(s) exit(s) #define Exit(s) exit(s)
#define Abort() abort() #define Abort() abort()
#define Pthread_create(t,attr,s,arg) pthread_create(t,attr,s,arg)
#define Pthread_join(t,ptr) pthread_join(t,ptr)
#define Mkstemp(t) mkstemp(t) #define Mkstemp(t) mkstemp(t)
#define Readline(p) readline(p) #define Readline(p) readline(p)
@ -265,6 +281,11 @@ void Add_history(const char *string);
#define Read_history(f) read_history(f) #define Read_history(f) read_history(f)
#define Add_history(s) add_history(s) #define Add_history(s) add_history(s)
#define Gzdopen(f,m) gzdopen(f,m)
#define Gzread(f,b,l) gzread(f,b,l)
#define Gzwrite(f,b,l) gzwrite(f,b,l)
#define Gzclose(f) gzclose(f)
#endif /* !WITH_SYCLS */ #endif /* !WITH_SYCLS */
#endif /* !defined(__sycls_h_included) */ #endif /* !defined(__sycls_h_included) */

View file

@ -67,10 +67,11 @@
#if HAVE_FCNTL_H #if HAVE_FCNTL_H
#include <fcntl.h> /* open(), O_RDWR */ #include <fcntl.h> /* open(), O_RDWR */
#endif #endif
#include <pthread.h>
#if HAVE_NETDB_H && (_WITH_IP4 || _WITH_IP6) #if HAVE_NETDB_H && (_WITH_IP4 || _WITH_IP6)
#include <netdb.h> /* struct hostent, gethostbyname() */ #include <netdb.h> /* struct hostent, gethostbyname() */
#endif #endif
#if HAVE_SYS_UN_H && WITH_UNIX #if HAVE_SYS_UN_H && _WITH_UNIX
#include <sys/un.h> /* struct sockaddr_un, unix domain sockets */ #include <sys/un.h> /* struct sockaddr_un, unix domain sockets */
#endif #endif
#if HAVE_SYS_IOCTL_H #if HAVE_SYS_IOCTL_H

View file

@ -402,7 +402,7 @@ const char *hstrerror(int err) {
#endif /* !HAVE_HSTRERROR */ #endif /* !HAVE_HSTRERROR */
#if WITH_TCP || WITH_UDP #if _WITH_TCP || _WITH_UDP
/* returns port in network byte order */ /* returns port in network byte order */
int parseport(const char *portname, int ipproto) { int parseport(const char *portname, int ipproto) {
struct servent *se; struct servent *se;
@ -425,7 +425,7 @@ int parseport(const char *portname, int ipproto) {
return se->s_port; return se->s_port;
} }
#endif /* WITH_TCP || WITH_UDP */ #endif /* _WITH_TCP || _WITH_UDP */
#if WITH_IP4 || WITH_IP6 #if WITH_IP4 || WITH_IP6
/* check the systems interfaces for ifname and return its index /* check the systems interfaces for ifname and return its index

View file

@ -17,15 +17,15 @@ union xioin6_u {
union sockaddr_union { union sockaddr_union {
struct sockaddr soa; struct sockaddr soa;
#if WITH_UNIX #if _WITH_UNIX
struct sockaddr_un un; struct sockaddr_un un;
#endif /* WITH_UNIX */ #endif /* _WITH_UNIX */
#if WITH_IP4 #if _WITH_IP4
struct sockaddr_in ip4; struct sockaddr_in ip4;
#endif /* WITH_IP4 */ #endif /* _WITH_IP4 */
#if WITH_IP6 #if _WITH_IP6
struct sockaddr_in6 ip6; struct sockaddr_in6 ip6;
#endif /* WITH_IP6 */ #endif /* _WITH_IP6 */
} ; } ;
#if _WITH_IP4 #if _WITH_IP4

429
test.sh
View file

@ -25,7 +25,7 @@ export SOCAT_OPTS="$opts"
#debug="1" #debug="1"
debug= debug=
TESTS="$@" TESTS="$@"
INTERFACE=eth0; # not used for function tests INTERFACE=eth1; # not used for function tests
MCINTERFACE=lo # !!! Linux only MCINTERFACE=lo # !!! Linux only
#LOCALHOST=192.168.58.1 #LOCALHOST=192.168.58.1
#LOCALHOST=localhost #LOCALHOST=localhost
@ -45,6 +45,16 @@ if ! type usleep >/dev/null 2>&1; then
sleep $(((n+999999)/1000000)) sleep $(((n+999999)/1000000))
} }
fi fi
# a "real value" sleep
rsleep () {
local n="$1"
local s="${n%.*}"
local u="${n#*.}"
sleep "$s"
usleep "$((u*10**(6-${#u})))"
}
#USLEEP=usleep #USLEEP=usleep
F_n="%3d" # format string for test numbers F_n="%3d" # format string for test numbers
LANG=C LANG=C
@ -89,7 +99,7 @@ esac
# for some tests we need a second local IPv4 address # for some tests we need a second local IPv4 address
case "$UNAME" in case "$UNAME" in
Linux) Linux)
BROADCASTIF=eth0 BROADCASTIF=eth1
SECONDADDR=127.0.0.2 SECONDADDR=127.0.0.2
BCADDR=127.255.255.255 BCADDR=127.255.255.255
BCIFADDR=$($IFCONFIG $BROADCASTIF |grep 'inet ' |awk '{print($2);}' |cut -d: -f2) ;; BCIFADDR=$($IFCONFIG $BROADCASTIF |grep 'inet ' |awk '{print($2);}' |cut -d: -f2) ;;
@ -124,7 +134,7 @@ case "$UNAME" in
esac esac
if [ -z "$SECONDIP6ADDR" ]; then if [ -z "$SECONDIP6ADDR" ]; then
case "$TESTS" in case "$TESTS" in
*%root2%*) $IFCONFIG eth0 ::2/128 *%root2%*) $IFCONFIG eth1 ::2/128
esac esac
fi fi
@ -468,7 +478,7 @@ N=1
#for o in $(filloptionvalues $OPTS|tr ',' ' '); do #for o in $(filloptionvalues $OPTS|tr ',' ' '); do
# echo testing if $METHOD accepts option $o # echo testing if $METHOD accepts option $o
# touch $TF # touch $TF
# $SOCAT $opts -!!$method:$TF,$o /dev/null,ignoreof </dev/null # $SOCAT $opts $method:$TF,$o%- /dev/null,ignoreof </dev/null
# rm -f $TF # rm -f $TF
#done #done
@ -971,7 +981,7 @@ for addr in create; do
for o in $(filloptionvalues $OPTS|tr ',' ' '); do for o in $(filloptionvalues $OPTS|tr ',' ' '); do
echo testing if $ADDR accepts option $o echo testing if $ADDR accepts option $o
rm -f $TF rm -f $TF
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null $SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
rm -f $TF rm -f $TF
done done
done done
@ -1099,7 +1109,7 @@ for addr in open; do
for o in $(filloptionvalues $OPTS|tr ',' ' '); do for o in $(filloptionvalues $OPTS|tr ',' ' '); do
echo testing if $ADDR on file accepts option $o echo testing if $ADDR on file accepts option $o
touch $TF touch $TF
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null $SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
rm -f $TF rm -f $TF
done done
done done
@ -1129,7 +1139,7 @@ for addr in gopen; do
for o in $(filloptionvalues $OPTS|tr ',' ' '); do for o in $(filloptionvalues $OPTS|tr ',' ' '); do
echo testing if $ADDR on new file accepts option $o echo testing if $ADDR on new file accepts option $o
rm -f $TF rm -f $TF
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null $SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
rm -f $TF rm -f $TF
done done
@ -1147,7 +1157,7 @@ for addr in gopen; do
for o in $(filloptionvalues $OPTS|tr ',' ' '); do for o in $(filloptionvalues $OPTS|tr ',' ' '); do
echo testing if $ADDR on existing file accepts option $o echo testing if $ADDR on existing file accepts option $o
rm -f $TF; touch $TF rm -f $TF; touch $TF
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null $SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
rm -f $TF rm -f $TF
done done
@ -1183,7 +1193,7 @@ for addr in gopen; do
for o in $(filloptionvalues $OPTS|tr ',' ' '); do for o in $(filloptionvalues $OPTS|tr ',' ' '); do
echo testing if $ADDR on socket accepts option $o echo testing if $ADDR on socket accepts option $o
rm -f $TF; $SOCAT - UNIX-L:$TF & pid=$! rm -f $TF; $SOCAT - UNIX-L:$TF & pid=$!
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null $SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
kill $pid 2>/dev/null kill $pid 2>/dev/null
rm -f $TF rm -f $TF
done done
@ -1203,7 +1213,7 @@ for addr in gopen; do
for o in $(filloptionvalues $OPTS|tr ',' ' '); do for o in $(filloptionvalues $OPTS|tr ',' ' '); do
echo testing if $ADDR on existing device accepts option $o echo testing if $ADDR on existing device accepts option $o
rm -f $TF; mknod $TF c 1 3 rm -f $TF; mknod $TF c 1 3
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null $SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
done done
else else
TEST="$ADDR on existing device accepts all its options" TEST="$ADDR on existing device accepts all its options"
@ -1219,7 +1229,7 @@ for addr in gopen; do
#echo $OPTS #echo $OPTS
for o in $(filloptionvalues $OPTS|tr ',' ' '); do for o in $(filloptionvalues $OPTS|tr ',' ' '); do
echo testing if $ADDR on existing device accepts option $o echo testing if $ADDR on existing device accepts option $o
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null $SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
done done
fi fi
@ -1425,7 +1435,7 @@ testecho () {
local arg1="$3"; [ -z "$arg1" ] && arg1="-" local arg1="$3"; [ -z "$arg1" ] && arg1="-"
local arg2="$4"; [ -z "$arg2" ] && arg2="echo" local arg2="$4"; [ -z "$arg2" ] && arg2="echo"
local opts="$5" local opts="$5"
local T="$6"; [ -z "$T" ] && T=0 local T="$6"; [ -z "$T" ] && T=0; export T
local tf="$td/test$N.stdout" local tf="$td/test$N.stdout"
local te="$td/test$N.stderr" local te="$td/test$N.stderr"
local tdiff="$td/test$N.diff" local tdiff="$td/test$N.diff"
@ -1435,7 +1445,7 @@ testecho () {
$PRINTF "test $F_n %s... " $num "$title" $PRINTF "test $F_n %s... " $num "$title"
#echo "$da" |$cmd >"$tf" 2>"$te" #echo "$da" |$cmd >"$tf" 2>"$te"
#set -vx #set -vx
(echo "$da"; sleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" & (echo "$da"; rsleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" &
export rc1=$! export rc1=$!
#sleep 5 && kill $rc1 2>/dev/null & #sleep 5 && kill $rc1 2>/dev/null &
# rc2=$! # rc2=$!
@ -1461,6 +1471,44 @@ testecho () {
fi fi
} }
# special function for use with the test address of socat V2 chains
testchain () {
local num="$1"
local title="$2"
local arg1="$3"; [ -z "$arg1" ] && arg1="-"
local arg2="$4"; [ -z "$arg2" ] && arg2="echo"
local opts="$5"
local suffix="$6" # what is to be appended by tests
local T="$7"; [ -z "$T" ] && T=0; export T
local tf="$td/test$N.stdout"
local te="$td/test$N.stderr"
local tdiff="$td/test$N.diff"
local da="$(date)"
$PRINTF "test $F_n %s... " $num "$title"
(echo "$da"; rsleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" &
export rc1=$!
wait $rc1
if [ "$?" != 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$SOCAT $opts $arg1 $arg2"
cat "$te"
numFAIL=$((numFAIL+1))
elif echo -e "$da\n$suffix\c" |diff - "$tf" >"$tdiff" 2>&1; then
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat $te; fi
numOK=$((numOK+1))
else
$PRINTF "$FAILED:\n"
echo "$SOCAT $opts $arg1 $arg2"
cat "$te"
echo diff:
cat "$tdiff"
numFAIL=$((numFAIL+1))
fi
}
# test if call to od and throughput of data works - with graceful shutdown and # test if call to od and throughput of data works - with graceful shutdown and
# flush of od buffers # flush of od buffers
testod () { testod () {
@ -1469,14 +1517,14 @@ testod () {
local arg1="$3"; [ -z "$arg1" ] && arg1="-" local arg1="$3"; [ -z "$arg1" ] && arg1="-"
local arg2="$4"; [ -z "$arg2" ] && arg2="echo" local arg2="$4"; [ -z "$arg2" ] && arg2="echo"
local opts="$5" local opts="$5"
local T="$6"; [ -z "$T" ] && T=0 local T="$6"; [ -z "$T" ] && T=0; export T
local tf="$td/test$N.stdout" local tf="$td/test$N.stdout"
local te="$td/test$N.stderr" local te="$td/test$N.stderr"
local tdiff="$td/test$N.diff" local tdiff="$td/test$N.diff"
local dain="$(date)" local dain="$(date)"
local daout="$(echo "$dain" |od -c)" local daout="$(echo "$dain" |od -c)"
$PRINTF "test $F_n %s... " $num "$title" $PRINTF "test $F_n %s... " $num "$title"
(echo "$dain"; sleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" (echo "$dain"; rsleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te"
if [ "$?" != 0 ]; then if [ "$?" != 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n" $PRINTF "$FAILED: $SOCAT:\n"
echo "$SOCAT $opts $arg1 $arg2" echo "$SOCAT $opts $arg1 $arg2"
@ -1816,17 +1864,20 @@ gentestcert () {
local name="$1" local name="$1"
if [ -f $name.key -a -f $name.crt -a -f $name.pem ]; then return; fi if [ -f $name.key -a -f $name.crt -a -f $name.pem ]; then return; fi
openssl genrsa $OPENSSL_RAND -out $name.key 768 >/dev/null 2>&1 openssl genrsa $OPENSSL_RAND -out $name.key 768 >/dev/null 2>&1
openssl req -new -config testcert.conf -key $name.key -x509 -out $name.crt >/dev/null 2>&1 openssl req -new -config testcert.conf -key $name.key -x509 -days 3653 -out $name.crt >/dev/null 2>&1
cat $name.key $name.crt >$name.pem cat $name.key $name.crt >$name.pem
} }
# generate a test DSA key and certificate # generate a test DSA key and certificate
gentestdsacert () { gentestdsacert () {
#set -vx
local name="$1" local name="$1"
if [ -f $name.key -a -f $name.crt -a -f $name.pem ]; then return; fi if [ -f $name.key -a -f $name.crt -a -f $name.pem ]; then
return;
fi
openssl dsaparam -out $name-dsa.pem 512 >/dev/null 2>&1 openssl dsaparam -out $name-dsa.pem 512 >/dev/null 2>&1
openssl dhparam -dsaparam -out $name-dh.pem 512 >/dev/null 2>&1 openssl dhparam -dsaparam -out $name-dh.pem 512 >/dev/null 2>&1
openssl req -newkey dsa:$name-dsa.pem -keyout $name.key -nodes -x509 -config testcert.conf -out $name.crt >/dev/null 2>&1 openssl req -newkey dsa:$name-dsa.pem -keyout $name.key -nodes -x509 -days 3653 -config testcert.conf -out $name.crt >/dev/null 2>&1
cat $name-dsa.pem $name-dh.pem $name.key $name.crt >$name.pem cat $name-dsa.pem $name-dh.pem $name.key $name.crt >$name.pem
} }
@ -1861,8 +1912,8 @@ N=$((N+1))
NAME=DUALSTDIO NAME=DUALSTDIO
case "$TESTS" in case "$TESTS" in
*%functions%*|*%stdio%*|*%$NAME%*) *%functions%*|*%stdio%*|*%$NAME%*)
TEST="$NAME: splitted form of stdio ('stdin!!stdout') with simple echo via internal pipe" TEST="$NAME: splitted form of stdio ('stdout%stdin') with simple echo via internal pipe"
testecho "$N" "$TEST" "stdin!!stdout" "pipe" "$opts" testecho "$N" "$TEST" "stdout%stdin" "pipe" "$opts"
esac esac
N=$((N+1)) N=$((N+1))
@ -1870,8 +1921,8 @@ N=$((N+1))
NAME=DUALSHORTSTDIO NAME=DUALSHORTSTDIO
case "$TESTS" in case "$TESTS" in
*%functions%*|*%stdio%*|*%$NAME%*) *%functions%*|*%stdio%*|*%$NAME%*)
TEST="$NAME: short splitted form of stdio ('-!!-') with simple echo via internal pipe" TEST="$NAME: short splitted form of stdio ('-%-') with simple echo via internal pipe"
testecho "$N" "$TEST" "-!!-" "pipe" "$opts" testecho "$N" "$TEST" "-%-" "pipe" "$opts"
esac esac
N=$((N+1)) N=$((N+1))
@ -1880,7 +1931,7 @@ NAME=DUALFDS
case "$TESTS" in case "$TESTS" in
*%functions%*|*%fd%*|*%$NAME%*) *%functions%*|*%fd%*|*%$NAME%*)
TEST="$NAME: file descriptors with simple echo via internal pipe" TEST="$NAME: file descriptors with simple echo via internal pipe"
testecho "$N" "$TEST" "0!!1" "pipe" "$opts" testecho "$N" "$TEST" "1%0" "pipe" "$opts"
esac esac
N=$((N+1)) N=$((N+1))
@ -1897,14 +1948,15 @@ esac
N=$((N+1)) N=$((N+1))
NAME=DUALPIPE # does not work with <write>%<read>
case "$TESTS" in #NAME=DUALPIPE
*%functions%*|*%pipe%*|*%$NAME%*) #case "$TESTS" in
TEST="$NAME: simple echo via named pipe, specified twice" #*%functions%*|*%pipe%*|*%$NAME%*)
tp="$td/pipe$N" #TEST="$NAME: simple echo via named pipe, specified twice"
testecho "$N" "$TEST" "" "pipe:$tp,nonblock!!pipe:$tp" "$opts" #tp="$td/pipe$N"
esac #testecho "$N" "$TEST" "" "pipe:$tp%pipe:$tp,nonblock" "$opts"
N=$((N+1)) #esac
#N=$((N+1))
NAME=FILE NAME=FILE
@ -1912,7 +1964,7 @@ case "$TESTS" in
*%functions%*|*%file%*|*%ignoreeof%*|*%$NAME%*) *%functions%*|*%file%*|*%ignoreeof%*|*%$NAME%*)
TEST="$NAME: simple echo via file" TEST="$NAME: simple echo via file"
tf="$td/file$N" tf="$td/file$N"
testecho "$N" "$TEST" "" "$tf,ignoreeof!!$tf" "$opts" testecho "$N" "$TEST" "" "$tf%$tf,ignoreeof" "$opts"
esac esac
N=$((N+1)) N=$((N+1))
@ -1994,7 +2046,8 @@ NAME=DUALSYSTEMFDS
case "$TESTS" in case "$TESTS" in
*%functions%*|*%system%*|*%$NAME%*) *%functions%*|*%system%*|*%$NAME%*)
TEST="$NAME: echo via dual system() of cat" TEST="$NAME: echo via dual system() of cat"
testecho "$N" "$TEST" "system:$CAT>&6,fdout=6!!system:$CAT<&7,fdin=7" "" "$opts" #testecho "$N" "$TEST" "system:'strace -tt -o /tmp/cat.out cat'>&6,fdout=6!!system:$CAT<&7,fdin=7" "" "$opts" "$T"
testecho "$N" "$TEST" "system:$CAT<&7,fdin=7%system:'cat'>&6,fdout=6" "" "$opts" "0.1"
esac esac
N=$((N+1)) N=$((N+1))
@ -2003,7 +2056,7 @@ NAME=EXECSOCKETFLUSH
case "$TESTS" in case "$TESTS" in
*%functions%*|*%exec%*|*%$NAME%*) *%functions%*|*%exec%*|*%$NAME%*)
TEST="$NAME: call to od via exec with socketpair" TEST="$NAME: call to od via exec with socketpair"
testod "$N" "$TEST" "" "exec:$OD_C" "$opts" testod "$N" "$TEST" "" "exec:$OD_C" "$opts" "0.1"
esac esac
N=$((N+1)) N=$((N+1))
@ -2012,7 +2065,7 @@ NAME=SYSTEMSOCKETFLUSH
case "$TESTS" in case "$TESTS" in
*%functions%*|*%system%*|*%$NAME%*) *%functions%*|*%system%*|*%$NAME%*)
TEST="$NAME: call to od via system() with socketpair" TEST="$NAME: call to od via system() with socketpair"
testod "$N" "$TEST" "" "system:$OD_C" "$opts" testod "$N" "$TEST" "" "system:$OD_C" "$opts" "0.1"
esac esac
N=$((N+1)) N=$((N+1))
@ -2081,7 +2134,7 @@ N=$((N+1))
#case "$TESTS" in #case "$TESTS" in
#*%functions%*|*%system%*|*%$NAME%*) #*%functions%*|*%system%*|*%$NAME%*)
#TEST="$NAME: call to od via dual system()" #TEST="$NAME: call to od via dual system()"
#testecho "$N" "$TEST" "system:$OD_C>&6,fdout=6!!system:$CAT<&7,fdin=7" "" "$opts" #testecho "$N" "$TEST" "system:$CAT<&7,fdin=7%system:$OD_C>&6,fdout=6" "" "$opts"
#esac #esac
#N=$((N+1)) #N=$((N+1))
@ -2227,7 +2280,7 @@ TEST="$NAME: echo via two unidirectional UDP IPv4 sockets"
tf="$td/file$N" tf="$td/file$N"
p1=$PORT p1=$PORT
p2=$((PORT+1)) p2=$((PORT+1))
testecho "$N" "$TEST" "" "udp:127.0.0.1:$p2,sp=$p1!!udp:127.0.0.1:$p1,sp=$p2" "$opts" testecho "$N" "$TEST" "" "udp:127.0.0.1:$p1,sp=$p2%udp:127.0.0.1:$p2,sp=$p1" "$opts"
esac esac
PORT=$((PORT+2)) PORT=$((PORT+2))
N=$((N+1)) N=$((N+1))
@ -2248,7 +2301,7 @@ ts="$td/test$N.socket"
tdiff="$td/test$N.diff" tdiff="$td/test$N.diff"
da=$(date) da=$(date)
CMD1="$SOCAT $opts UNIX-LISTEN:$ts PIPE" CMD1="$SOCAT $opts UNIX-LISTEN:$ts PIPE"
CMD2="$SOCAT $opts -!!- UNIX:$ts" CMD2="$SOCAT $opts -%- UNIX:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD1 </dev/null >$tf 2>"${te}1" & $CMD1 </dev/null >$tf 2>"${te}1" &
bg=$! # background process id bg=$! # background process id
@ -2285,7 +2338,7 @@ tsl=$PORT
ts="127.0.0.1:$tsl" ts="127.0.0.1:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts TCP4-LISTEN:$tsl,reuseaddr PIPE" CMD1="$SOCAT $opts TCP4-LISTEN:$tsl,reuseaddr PIPE"
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" & $CMD1 >"$tf" 2>"${te}1" &
waittcp4port $tsl 1 waittcp4port $tsl 1
@ -2325,7 +2378,7 @@ tsl=$PORT
ts="[::1]:$tsl" ts="[::1]:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts TCP6-listen:$tsl,reuseaddr PIPE" CMD1="$SOCAT $opts TCP6-listen:$tsl,reuseaddr PIPE"
CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts" CMD2="$SOCAT $opts stdout%stdin TCP6:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" & $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
@ -2371,7 +2424,7 @@ tsl=$PORT
ts="127.0.0.1:$tsl" ts="127.0.0.1:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts TCP-listen:$tsl,pf=ip4,reuseaddr PIPE" CMD1="$SOCAT $opts TCP-listen:$tsl,pf=ip4,reuseaddr PIPE"
CMD2="$SOCAT $opts stdin!!stdout TCP:$ts" CMD2="$SOCAT $opts stdout%stdin TCP:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" & $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
@ -2417,7 +2470,7 @@ tsl=$PORT
ts="[::1]:$tsl" ts="[::1]:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts TCP-listen:$tsl,pf=ip6,reuseaddr PIPE" CMD1="$SOCAT $opts TCP-listen:$tsl,pf=ip6,reuseaddr PIPE"
CMD2="$SOCAT $opts stdin!!stdout TCP:$ts" CMD2="$SOCAT $opts stdout%stdin TCP:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" & $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
@ -2465,7 +2518,7 @@ tsl=$PORT
ts="127.0.0.1:$tsl" ts="127.0.0.1:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts TCP6-listen:$tsl,ipv6-v6only=0,reuseaddr PIPE" CMD1="$SOCAT $opts TCP6-listen:$tsl,ipv6-v6only=0,reuseaddr PIPE"
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" & $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
@ -2513,7 +2566,7 @@ tsl=$PORT
ts="127.0.0.1:$tsl" ts="127.0.0.1:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts TCP6-listen:$tsl,ipv6-v6only=1,reuseaddr PIPE" CMD1="$SOCAT $opts TCP6-listen:$tsl,ipv6-v6only=1,reuseaddr PIPE"
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" & $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
@ -2558,7 +2611,7 @@ tsl=$PORT
ts="127.0.0.1:$tsl" ts="127.0.0.1:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts TCP-listen:$tsl,reuseaddr PIPE" CMD1="$SOCAT $opts TCP-listen:$tsl,reuseaddr PIPE"
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" & SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
@ -2603,7 +2656,7 @@ tsl=$PORT
ts="[::1]:$tsl" ts="[::1]:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts TCP-listen:$tsl,reuseaddr PIPE" CMD1="$SOCAT $opts TCP-listen:$tsl,reuseaddr PIPE"
CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts" CMD2="$SOCAT $opts stdout%stdin TCP6:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" & SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
@ -2651,7 +2704,7 @@ tsl=$PORT
ts="127.0.0.1:$tsl" ts="127.0.0.1:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts -4 TCP-listen:$tsl,reuseaddr PIPE" CMD1="$SOCAT $opts -4 TCP-listen:$tsl,reuseaddr PIPE"
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" & SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
@ -2696,7 +2749,7 @@ tsl=$PORT
ts="[::1]:$tsl" ts="[::1]:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts -6 TCP-listen:$tsl,reuseaddr PIPE" CMD1="$SOCAT $opts -6 TCP-listen:$tsl,reuseaddr PIPE"
CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts" CMD2="$SOCAT $opts stdout%stdin TCP6:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" & SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
@ -2745,7 +2798,7 @@ tsl=$PORT
ts="127.0.0.1:$tsl" ts="127.0.0.1:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts -6 TCP-listen:$tsl,pf=ip4,reuseaddr PIPE" CMD1="$SOCAT $opts -6 TCP-listen:$tsl,pf=ip4,reuseaddr PIPE"
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" & SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
@ -2790,7 +2843,7 @@ tsl=$PORT
ts="[::1]:$tsl" ts="[::1]:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts -4 TCP-listen:$tsl,pf=ip6,reuseaddr PIPE" CMD1="$SOCAT $opts -4 TCP-listen:$tsl,pf=ip6,reuseaddr PIPE"
CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts" CMD2="$SOCAT $opts stdout%stdin TCP6:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" & SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
@ -2915,7 +2968,7 @@ te="$td/test$N.stderr"
tdiff="$td/test$N.diff" tdiff="$td/test$N.diff"
da=$(date) da=$(date)
echo "$da" >$tf1 echo "$da" >$tf1
CMD="$SOCAT $opts $tf1!!/dev/null /dev/null,ignoreeof!!-" CMD="$SOCAT $opts /dev/null%$tf1 -%/dev/null,ignoreeof"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD >"$tf2" 2>"$te" $CMD >"$tf2" 2>"$te"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
@ -2945,7 +2998,7 @@ tf="$td/test$N.stdout"
te="$td/test$N.stderr" te="$td/test$N.stderr"
tdiff="$td/test$N.diff" tdiff="$td/test$N.diff"
da=$(date) da=$(date)
CMD="$SOCAT $opts $tp!!/dev/null /dev/null,ignoreeof!!$tf" CMD="$SOCAT $opts /dev/null%$tp $tf%/dev/null,ignoreeof"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
#mknod $tp p # no mknod p on FreeBSD #mknod $tp p # no mknod p on FreeBSD
mkfifo $tp mkfifo $tp
@ -3121,9 +3174,9 @@ case "$TESTS" in
TEST="$NAME: exec against address with ignoreeof" TEST="$NAME: exec against address with ignoreeof"
tf="$td/test$N.stdout" tf="$td/test$N.stdout"
te="$td/test$N.stderr" te="$td/test$N.stderr"
CMD="$SOCAT $opts -lf /dev/null EXEC:$TRUE /dev/null,ignoreeof" CMD="$SOCAT $opts -lf "$te" EXEC:$TRUE /dev/null,ignoreeof"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD >"$tf" 2>"$te" $CMD >"$tf"
if [ -s "$te" ]; then if [ -s "$te" ]; then
$PRINTF "$FAILED: $SOCAT:\n" $PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD" echo "$CMD"
@ -3337,6 +3390,119 @@ esac
N=$((N+1)) N=$((N+1))
NAME=CHAIN
case "$TESTS" in
*%functions%*|*%chain%*|*%$NAME%*)
TEST="$NAME: stdio to test+pipe"
testchain "$N" "$TEST" "stdio" "test|pipe" "$opts" "><"
esac
N=$((N+1))
NAME=REVCHAIN
case "$TESTS" in
*%functions%*|*%chain%*|*%$NAME%*)
TEST="$NAME: stdio to rev.test+pipe"
testchain "$N" "$TEST" "stdio" "^test|pipe" "$opts" "<>"
esac
N=$((N+1))
NAME=TWOCHAINS
case "$TESTS" in
*%functions%*|*%chain%*|*%$NAME%*)
TEST="$NAME: test+stdio vs. test+pipe"
testchain "$N" "$TEST" "test|stdio" "test|pipe" "$opts" "<><>"
esac
N=$((N+1))
NAME=TWOREVCHAINS
case "$TESTS" in
*%functions%*|*%chain%*|*%$NAME%*)
TEST="$NAME: rev.test+stdio vs. rev.test+pipe"
testchain "$N" "$TEST" "^test|stdio" "^test|pipe" "$opts" "><><"
esac
N=$((N+1))
NAME=LONGCHAIN
case "$TESTS" in
*%functions%*|*%chain%*|*%$NAME%*)
TEST="$NAME: stdio vs. four-tests+pipe"
testchain "$N" "$TEST" "stdio" "test|^test|test|^test|pipe" "$opts" "><><><><"
esac
N=$((N+1))
NAME=TOWLONGCHAINS
case "$TESTS" in
*%functions%*|*%chain%*|*%$NAME%*)
TEST="$NAME: four-tests+stdio vs. four-tests+pipe"
testchain "$N" "$TEST" "^test|test|^test|test|stdio" "test|^test|test|^test|pipe" "$opts" "<><>><><><><<><>"
esac
N=$((N+1))
NAME=CHAINSPACES
case "$TESTS" in
*%functions%*|*%chain%*|*%$NAME%*)
TEST="$NAME: lot of test with spaces"
testchain "$N" "$TEST" " ^ test | test | ^ test | test | stdio " " test | ^ test | test | ^ test | pipe " "$opts" "<><>><><><><<><>"
esac
N=$((N+1))
NAME=CHAINUNIDIR
case "$TESTS" in
*%functions%*|*%chain%*|*%$NAME%*)
TEST="$NAME: two unidirectional chains"
testchain "$N" "$TEST" "test|stdin" "test|stdout" "-u $opts" "<>"
esac
N=$((N+1))
NAME=CHAINREVDIR
case "$TESTS" in
*%functions%*|*%chain%*|*%$NAME%*)
TEST="$NAME: two unidirectional chains, right to left"
testchain "$N" "$TEST" "^test|stdout" "^test|stdin" "-U $opts" "><"
esac
N=$((N+1))
NAME=CHAINDUAL
case "$TESTS" in
*%functions%*|*%chain%*|*%dual%*|*%$NAME%*)
TEST="$NAME: bidirectional dual chain (uni/rev)"
testchain "$N" "$TEST" "stdio" "testuni%testrev|pipe" "$opts" "><"
esac
N=$((N+1))
NAME=CHAINDUAL2
case "$TESTS" in
*%functions%*|*%chain%*|*%dual%*|*%$NAME%*)
TEST="$NAME: bidirectional dual chain (bi/rev)"
testchain "$N" "$TEST" "stdio" "test%testrev|pipe" "$opts" "><"
esac
N=$((N+1))
NAME=CHAINDUAL3
case "$TESTS" in
*%functions%*|*%chain%*|*%dual%*|*%$NAME%*)
TEST="$NAME: bidirectional dual chain (uni/bi)"
testchain "$N" "$TEST" "stdio" "testuni%^test|pipe" "$opts" "><"
esac
N=$((N+1))
NAME=CHAINDUAL4
case "$TESTS" in
*%functions%*|*%chain%*|*%dual%*|*%$NAME%*)
TEST="$NAME: bidirectional dual chain (bi/bi)"
testchain "$N" "$TEST" "stdio" "test%^test|pipe" "$opts" "><"
esac
N=$((N+1))
NAME=CHAINDUAL5
case "$TESTS" in
*%functions%*|*%chain%*|*%dual%*|*%$NAME%*)
TEST="$NAME: bidirectional mixed normal and dual chains"
testchain "$N" "$TEST" "test|test%^test|^test|stdio" "^test|testuni%testrev|test|pipe" "$opts" "><<<>><<>>><"
esac
N=$((N+1))
NAME=OPENSSL_TCP4 NAME=OPENSSL_TCP4
case "$TESTS" in case "$TESTS" in
*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) *%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
@ -3358,12 +3524,15 @@ tdiff="$td/test$N.diff"
da=$(date) da=$(date)
CMD2="$SOCAT $opts exec:'openssl s_server -accept "$PORT" -quiet -cert testsrv.pem' pipe" CMD2="$SOCAT $opts exec:'openssl s_server -accept "$PORT" -quiet -cert testsrv.pem' pipe"
#! CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT" #! CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT"
CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD" #CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD"
CMD="$SOCAT $opts - openssl,verify=0,$SOCAT_EGD|tcp4:$LOCALHOST:$PORT"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
eval "$CMD2 2>\"${te}1\" &" eval "$CMD2 2>\"${te}1\" &"
pid=$! # background process id pid=$! # background process id
waittcp4port $PORT waittcp4port $PORT
echo "$da" |$CMD >$tf 2>"${te}2" # the openssl s_server program appears to not support half closed connections,
# so we must delay EOF
(echo "$da"; sleep 1) |$CMD >$tf 2>"${te}2"
if ! echo "$da" |diff - "$tf" >"$tdiff"; then if ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED: $SOCAT:\n" $PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD2 &" echo "$CMD2 &"
@ -3401,8 +3570,10 @@ tf="$td/test$N.stdout"
te="$td/test$N.stderr" te="$td/test$N.stderr"
tdiff="$td/test$N.diff" tdiff="$td/test$N.diff"
da=$(date) da=$(date)
CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe" #CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe"
CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD" CMD2="$SOCAT $opts TCP4-LISTEN:$PORT,reuseaddr ^OPENSSL-LISTEN,$SOCAT_EGD',cert=testsrv.crt,key=testsrv.key,verify=0|pipe'"
#CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,,verify=0,$SOCAT_EGD"
CMD="$SOCAT $opts - openssl,verify=0,$SOCAT_EGD|tcp4:$LOCALHOST:$PORT"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
eval "$CMD2 2>\"${te}1\" &" eval "$CMD2 2>\"${te}1\" &"
pid=$! # background process id pid=$! # background process id
@ -3625,7 +3796,8 @@ tdiff="$td/test$N.diff"
da="$(date)" da="$da$($ECHO '\r')" da="$(date)" da="$da$($ECHO '\r')"
# we have a normal tcp echo listening - so the socks header must appear in answer # we have a normal tcp echo listening - so the socks header must appear in answer
CMD2="$SOCAT tcp4-l:$PORT,reuseaddr exec:\"./socks4echo.sh\"" CMD2="$SOCAT tcp4-l:$PORT,reuseaddr exec:\"./socks4echo.sh\""
CMD="$SOCAT $opts - socks4:$LOCALHOST:32.98.76.54:32109,pf=ip4,socksport=$PORT",socksuser="nobody" #CMD="$SOCAT $opts - socks4:$LOCALHOST:32.98.76.54:32109,pf=ip4,socksport=$PORT",socksuser="nobody"
CMD="$SOCAT $opts - socks4:32.98.76.54:32109,socksuser=nobody|tcp4:$LOCALHOST:$PORT"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
eval "$CMD2 2>\"${te}1\" &" eval "$CMD2 2>\"${te}1\" &"
pid=$! # background process id pid=$! # background process id
@ -3712,7 +3884,8 @@ tdiff="$td/test$N.diff"
da="$(date)" da="$da$($ECHO '\r')" da="$(date)" da="$da$($ECHO '\r')"
# we have a normal tcp echo listening - so the socks header must appear in answer # we have a normal tcp echo listening - so the socks header must appear in answer
CMD2="$SOCAT tcp4-l:$PORT,reuseaddr exec:\"./socks4a-echo.sh\"" CMD2="$SOCAT tcp4-l:$PORT,reuseaddr exec:\"./socks4a-echo.sh\""
CMD="$SOCAT $opts - socks4a:$LOCALHOST:localhost:32109,pf=ip4,socksport=$PORT",socksuser="nobody" #CMD="$SOCAT $opts - socks4a:$LOCALHOST:localhost:32109,pf=ip4,socksport=$PORT",socksuser="nobody"
CMD="$SOCAT $opts - socks4a:localhost:32109,socksuser=nobody|tcp4:$LOCALHOST:$PORT"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
eval "$CMD2 2>\"${te}1\" &" eval "$CMD2 2>\"${te}1\" &"
pid=$! # background process id pid=$! # background process id
@ -3800,7 +3973,8 @@ tdiff="$td/test$N.diff"
da="$(date)" da="$da$($ECHO '\r')" da="$(date)" da="$da$($ECHO '\r')"
#CMD2="$SOCAT tcp4-l:$PORT,crlf system:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\"" #CMD2="$SOCAT tcp4-l:$PORT,crlf system:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\""
CMD2="$SOCAT tcp4-l:$PORT,reuseaddr,crlf exec:\"/bin/bash proxyecho.sh\"" CMD2="$SOCAT tcp4-l:$PORT,reuseaddr,crlf exec:\"/bin/bash proxyecho.sh\""
CMD="$SOCAT $opts - proxy:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT" #CMD="$SOCAT $opts - proxy:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT"
CMD="$SOCAT $opts - proxy:127.0.0.1:1000|tcp4:$LOCALHOST:$PORT"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
eval "$CMD2 2>\"${te}2\" &" eval "$CMD2 2>\"${te}2\" &"
pid=$! # background process id pid=$! # background process id
@ -3882,7 +4056,7 @@ tsl=$PORT
ts="127.0.0.1:$tsl" ts="127.0.0.1:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts TCP4-LISTEN:$tsl,reuseaddr exec:$CAT,nofork" CMD1="$SOCAT $opts TCP4-LISTEN:$tsl,reuseaddr exec:$CAT,nofork"
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
#$CMD1 >"$tf" 2>"${te}1" & #$CMD1 >"$tf" 2>"${te}1" &
$CMD1 >/dev/null 2>"${te}1" & $CMD1 >/dev/null 2>"${te}1" &
@ -3944,7 +4118,7 @@ N=$((N+1))
#da=$(date) #da=$(date)
#$SOCAT UDP-listen:$tsl PIPE & #$SOCAT UDP-listen:$tsl PIPE &
#sleep 2 #sleep 2
#echo "$da" |$SOCAT stdin!!stdout UDP:$ts >"$tf" #echo "$da" |$SOCAT stdout%stdin UDP:$ts >"$tf"
#if [ $? -eq 0 ] && echo "$da" |diff "$tf" -; then #if [ $? -eq 0 ] && echo "$da" |diff "$tf" -; then
# $ECHO "... test $N succeeded" # $ECHO "... test $N succeeded"
# numOK=$((numOK+1)) # numOK=$((numOK+1))
@ -4068,7 +4242,8 @@ tdiff="$td/test$N.diff"
da="$(date)" da="$da$($ECHO '\r')" da="$(date)" da="$da$($ECHO '\r')"
#CMD2="$SOCAT tcp-l:$PORT,crlf system:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\"" #CMD2="$SOCAT tcp-l:$PORT,crlf system:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\""
CMD2="$SOCAT tcp4-l:$PORT,reuseaddr,crlf exec:\"/bin/bash proxyecho.sh -w 2\"" CMD2="$SOCAT tcp4-l:$PORT,reuseaddr,crlf exec:\"/bin/bash proxyecho.sh -w 2\""
CMD="$SOCAT $opts - proxy:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT" #CMD="$SOCAT $opts - proxy:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT"
CMD="$SOCAT $opts - proxy:127.0.0.1:1000|tcp4:$LOCALHOST:$PORT"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
eval "$CMD2 2>\"${te}1\" &" eval "$CMD2 2>\"${te}1\" &"
pid=$! # background process id pid=$! # background process id
@ -4129,7 +4304,7 @@ NAME=SINGLEEXECOUTSOCKETPAIR
case "$TESTS" in case "$TESTS" in
*%functions%*|*%$NAME%*) *%functions%*|*%$NAME%*)
TEST="$NAME: inheritance of stdout to single exec with socketpair" TEST="$NAME: inheritance of stdout to single exec with socketpair"
testecho "$N" "$TEST" "-!!exec:cat" "" "$opts" 1 testecho "$N" "$TEST" "exec:cat%-" "" "$opts" 1
esac esac
N=$((N+1)) N=$((N+1))
@ -4137,7 +4312,7 @@ NAME=SINGLEEXECOUTPIPE
case "$TESTS" in case "$TESTS" in
*%functions%*|*%$NAME%*) *%functions%*|*%$NAME%*)
TEST="$NAME: inheritance of stdout to single exec with pipe" TEST="$NAME: inheritance of stdout to single exec with pipe"
testecho "$N" "$TEST" "-!!exec:cat,pipes" "" "$opts" 1 testecho "$N" "$TEST" "exec:cat,pipes%-" "" "$opts" 1
esac esac
N=$((N+1)) N=$((N+1))
@ -4149,7 +4324,7 @@ if ! testaddrs pty >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
else else
testecho "$N" "$TEST" "-!!exec:cat,pty,raw" "" "$opts" 1 testecho "$N" "$TEST" "exec:cat,pty,raw%-" "" "$opts" 1
fi fi
esac esac
N=$((N+1)) N=$((N+1))
@ -4158,7 +4333,7 @@ NAME=SINGLEEXECINSOCKETPAIR
case "$TESTS" in case "$TESTS" in
*%functions%*|*%$NAME%*) *%functions%*|*%$NAME%*)
TEST="$NAME: inheritance of stdin to single exec with socketpair" TEST="$NAME: inheritance of stdin to single exec with socketpair"
testecho "$N" "$TEST" "exec:cat!!-" "" "$opts" testecho "$N" "$TEST" "-%exec:cat" "" "$opts"
esac esac
N=$((N+1)) N=$((N+1))
@ -4166,7 +4341,7 @@ NAME=SINGLEEXECINPIPE
case "$TESTS" in case "$TESTS" in
*%functions%*|*%$NAME%*) *%functions%*|*%$NAME%*)
TEST="$NAME: inheritance of stdin to single exec with pipe" TEST="$NAME: inheritance of stdin to single exec with pipe"
testecho "$N" "$TEST" "exec:cat,pipes!!-" "" "$opts" testecho "$N" "$TEST" "-%exec:cat,pipes" "" "$opts"
esac esac
N=$((N+1)) N=$((N+1))
@ -4178,7 +4353,7 @@ if ! testaddrs pty >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
else else
testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts" $MISCDELAY testecho "$N" "$TEST" "-%exec:cat,pty,raw" "" "$opts" $MISCDELAY
fi fi
esac esac
N=$((N+1)) N=$((N+1))
@ -4191,7 +4366,7 @@ if ! testaddrs pty >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
else else
testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts" testecho "$N" "$TEST" "-%exec:cat,pty,raw" "" "$opts"
fi fi
esac esac
N=$((N+1)) N=$((N+1))
@ -4217,7 +4392,7 @@ tr="$td/test$N.ref"
tdiff="$td/test$N.diff" tdiff="$td/test$N.diff"
da="$(date)" da="$da$($ECHO '\r')" da="$(date)" da="$da$($ECHO '\r')"
# the feature that we really want to test is in the readline.sh script: # the feature that we really want to test is in the readline.sh script:
CMD="$SOCAT $opts open:$tpi,nonblock!!open:$tpo exec:\"./readline.sh -nh ./readline-test.sh\",pty,ctty,setsid,raw,echo=0,isig" CMD="$SOCAT $opts open:$tpo%open:$tpi,nonblock exec:\"./readline.sh -nh ./readline-test.sh\",pty,ctty,setsid,raw,echo=0,isig"
#echo "$CMD" >"$ts" #echo "$CMD" >"$ts"
#chmod a+x "$ts" #chmod a+x "$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
@ -4366,10 +4541,12 @@ CMD1="$SOCAT $opts -lpserver tcp4-l:$PORT,reuseaddr,bind=$LOCALHOST echo"
# this is the proxy in the protected network that provides a way out # this is the proxy in the protected network that provides a way out
CMD2="$SOCAT $opts -lpproxy tcp4-l:$((PORT+1)),reuseaddr,bind=$LOCALHOST,fork exec:./proxy.sh" CMD2="$SOCAT $opts -lpproxy tcp4-l:$((PORT+1)),reuseaddr,bind=$LOCALHOST,fork exec:./proxy.sh"
# this is our proxy connect wrapper in the protected network # this is our proxy connect wrapper in the protected network
CMD3="$SOCAT $opts -lpwrapper tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$LOCALHOST:$((PORT+3)),pf=ip4,proxyport=$((PORT+1)),resolve" #CMD3="$SOCAT $opts -lpwrapper tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$LOCALHOST:$((PORT+3)),pf=ip4,proxyport=$((PORT+1)),resolve"
CMD3="$SOCAT $opts -lpwrapper tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$((PORT+3)),resolve\\|tcp4:$LOCALHOST:$((PORT+1))"
# this is our double client in the protected network using SSL # this is our double client in the protected network using SSL
#CMD4="$SOCAT $opts -lp2client ssl:$LOCALHOST:$((PORT+2)),pf=ip4,retry=10,intervall=1,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD tcp4:$LOCALHOST:$PORT" #CMD4="$SOCAT $opts -lp2client ssl:$LOCALHOST:$((PORT+2)),pf=ip4,retry=10,intervall=1,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD tcp4:$LOCALHOST:$PORT"
CMD4="$SOCAT $opts -lp2client ssl:$LOCALHOST:$((PORT+2)),pf=ip4,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD tcp4:$LOCALHOST:$PORT" #CMD4="$SOCAT $opts -lp2client ssl:$LOCALHOST:$((PORT+2)),pf=ip4,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD tcp4:$LOCALHOST:$PORT"
CMD4="$SOCAT $opts -lp2client ssl,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD\|tcp4:$LOCALHOST:$((PORT+2)) tcp4:$LOCALHOST:$PORT"
# this is the double server in the outside network # this is the double server in the outside network
CMD5="$SOCAT $opts -lp2server -t1 tcp4-l:$((PORT+4)),reuseaddr,bind=$LOCALHOST ssl-l:$((PORT+3)),pf=ip4,reuseaddr,bind=$LOCALHOST,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt" CMD5="$SOCAT $opts -lp2server -t1 tcp4-l:$((PORT+4)),reuseaddr,bind=$LOCALHOST ssl-l:$((PORT+3)),pf=ip4,reuseaddr,bind=$LOCALHOST,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt"
# this is the outside client that wants to use the protected server # this is the outside client that wants to use the protected server
@ -4446,11 +4623,16 @@ CMD1="$SOCAT $opts -lpserver -t1 tcp4-l:$PORT,reuseaddr,bind=$LOCALHOST,fork ech
# this is the proxy in the protected network that provides a way out # this is the proxy in the protected network that provides a way out
CMD2="$SOCAT $opts -lpproxy -t1 tcp4-l:$((PORT+1)),reuseaddr,bind=$LOCALHOST,fork exec:./proxy.sh" CMD2="$SOCAT $opts -lpproxy -t1 tcp4-l:$((PORT+1)),reuseaddr,bind=$LOCALHOST,fork exec:./proxy.sh"
# this is our proxy connect wrapper in the protected network # this is our proxy connect wrapper in the protected network
CMD3="$SOCAT $opts -lpwrapper -t3 tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$LOCALHOST:$((PORT+3)),pf=ip4,proxyport=$((PORT+1)),resolve" #CMD3="$SOCAT $opts -lpwrapper -t3 tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$LOCALHOST:$((PORT+3)),pf=ip4,proxyport=$((PORT+1)),resolve"
CMD3="$SOCAT $opts -lu -lpwrapper -t3 tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$((PORT+3)),resolve\\|tcp4:$LOCALHOST:$((PORT+1))"
# this is our double client in the protected network using SSL # this is our double client in the protected network using SSL
CMD4="$SOCAT $opts -lp2client -t3 ssl:$LOCALHOST:$((PORT+2)),retry=10,intervall=1,cert=testcli.pem,cafile=testsrv.crt,verify,fork,$SOCAT_EGD tcp4:$LOCALHOST:$PORT" #CMD4="$SOCAT $opts -lp2client -t3 ssl:$LOCALHOST:$((PORT+2)),retry=10,intervall=1,cert=testcli.pem,cafile=testsrv.crt,verify,fork,$SOCAT_EGD tcp4:$LOCALHOST:$PORT"
#CMD4="$SOCAT $opts -lu -lp2client -t3 ssl,cert=testcli.pem,cafile=testsrv.crt,fork,$SOCAT_EGD,retry=10,intervall=1\\|tcp4:$LOCALHOST:$((PORT+2)) tcp4:$LOCALHOST:$PORT"
CMD4="$SOCAT $opts -lu -lp2client -t3 tcp4:$LOCALHOST:$((PORT+2)),fork ^ssl,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD,retry=10,intervall=1\\|tcp4:$LOCALHOST:$PORT"
# this is the double server in the outside network # this is the double server in the outside network
CMD5="$SOCAT $opts -lp2server -t4 tcp4-l:$((PORT+4)),reuseaddr,bind=$LOCALHOST,fork ssl-l:$((PORT+3)),pf=ip4,reuseaddr,bind=$LOCALHOST,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt,retry=10" #CMD5="$SOCAT $opts -lp2server -t4 tcp4-l:$((PORT+4)),reuseaddr,bind=$LOCALHOST,fork ssl-l:$((PORT+3)),pf=ip4,reuseaddr,bind=$LOCALHOST,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt,retry=10"
#CMD5="$SOCAT $opts -lp2server -t4 tcp4-l:$((PORT+4)),reuseaddr,bind=$LOCALHOST,fork tcp4-l:$((PORT+3)),reuseaddr,bind=$LOCALHOST,retry=10\\|ssl-l,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt"
CMD5="$SOCAT $opts -lp2server -t4 tcp4-l:$((PORT+4)),reuseaddr,bind=$LOCALHOST,fork ssl-l,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt\\|tcp4-l:$((PORT+3)),reuseaddr,bind=$LOCALHOST,retry=10"
# this is the outside client that wants to use the protected server # this is the outside client that wants to use the protected server
CMD6="$SOCAT $opts -lpclient -t5 - tcp4:$LOCALHOST:$((PORT+4)),retry=3" CMD6="$SOCAT $opts -lpclient -t5 - tcp4:$LOCALHOST:$((PORT+4)),retry=3"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
@ -4594,7 +4776,9 @@ testserversec () {
#set -vx #set -vx
# assemble address w/ security option; on dual, take read part: # assemble address w/ security option; on dual, take read part:
case "$arg1" in case "$arg1" in
*!!*) arg="${arg1%!!*},$secopt1!!${arg1#*!!}" ;; #*!!*) arg="${arg1%!!*},$secopt1!!${arg1#*!!}" ;;
#*%*) arg="${arg1%\%*}%${arg1#*%},$secopt1" ;;
*%*) arg="$arg1,$secopt1" ;;
*) arg="$arg1,$secopt1" ;; *) arg="$arg1,$secopt1" ;;
esac esac
# start server # start server
@ -5323,8 +5507,10 @@ tf="$td/test$N.stdout"
te="$td/test$N.stderr" te="$td/test$N.stderr"
tdiff="$td/test$N.diff" tdiff="$td/test$N.diff"
da=$(date) da=$(date)
CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cert=$SRVCERT.pem,key=$SRVCERT.key,verify=0 pipe" #CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cert=$SRVCERT.pem,key=$SRVCERT.key,verify=0 pipe"
CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD" CMD2="$SOCAT $opts TCP4-LISTEN:$PORT,reuseaddr ^OPENSSL-LISTEN,$SOCAT_EGD,cert=$SRVCERT.pem,key=$SRVCERT.key,verify=0\|pipe"
#CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD"
CMD="$SOCAT $opts - openssl,verify=0,$SOCAT_EGD|tcp4:$LOCALHOST:$PORT"
$PRINTF "test $F_n $TEST... " $N $PRINTF "test $F_n $TEST... " $N
eval "$CMD2 2>\"${te}1\" &" eval "$CMD2 2>\"${te}1\" &"
pid=$! # background process id pid=$! # background process id
@ -5690,7 +5876,7 @@ tsl=$PORT
ts="127.0.0.1:$tsl" ts="127.0.0.1:$tsl"
da=$(date) da=$(date)
CMD1="$SOCAT $opts TCP6-listen:$tsl,reuseaddr PIPE" CMD1="$SOCAT $opts TCP6-listen:$tsl,reuseaddr PIPE"
CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts" CMD2="$SOCAT $opts stdout%stdin TCP6:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" & $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
@ -6250,7 +6436,7 @@ PORT2=$PORT; PORT=$((PORT+1))
PORT3=$PORT PORT3=$PORT
# we use the forward channel (PORT1) for testing, and have a backward channel # we use the forward channel (PORT1) for testing, and have a backward channel
# (PORT2) to get the data back, so we get the classical echo behaviour # (PORT2) to get the data back, so we get the classical echo behaviour
testserversec "$N" "$TEST" "$opts -s" "udp4-recv:$PORT1,reuseaddr!!udp4-sendto:127.0.0.1:$PORT2" "" "sp=$PORT3" "udp4-recv:$PORT2!!udp4-sendto:127.0.0.1:$PORT1" 4 udp $PORT1 0 testserversec "$N" "$TEST" "$opts -s" "udp4-sendto:127.0.0.1:$PORT2%udp4-recv:$PORT1,reuseaddr" "" "sp=$PORT3" "udp4-sendto:127.0.0.1:$PORT1%udp4-recv:$PORT2" 4 udp $PORT1 0
fi fi
esac esac
PORT=$((PORT+1)) PORT=$((PORT+1))
@ -6268,7 +6454,7 @@ PORT1=$PORT; PORT=$((PORT+1))
PORT2=$PORT PORT2=$PORT
# we use the forward channel (PORT1) for testing, and have a backward channel # we use the forward channel (PORT1) for testing, and have a backward channel
# (PORT2) to get the data back, so we get the classical echo behaviour # (PORT2) to get the data back, so we get the classical echo behaviour
testserversec "$N" "$TEST" "$opts -s" "udp4-recv:$PORT1,reuseaddr!!udp4-sendto:127.0.0.1:$PORT2" "" "lowport" "udp4-recv:$PORT2!!udp4-sendto:127.0.0.1:$PORT1" 4 udp $PORT1 0 testserversec "$N" "$TEST" "$opts -s" "udp4-sendto:127.0.0.1:$PORT2%udp4-recv:$PORT1,reuseaddr" "" "lowport" "udp4-sendto:127.0.0.1:$PORT1%udp4-recv:$PORT2" 4 udp $PORT1 0
fi fi
esac esac
PORT=$((PORT+1)) PORT=$((PORT+1))
@ -6286,7 +6472,7 @@ PORT1=$PORT; PORT=$((PORT+1))
PORT2=$PORT PORT2=$PORT
# we use the forward channel (PORT1) for testing, and have a backward channel # we use the forward channel (PORT1) for testing, and have a backward channel
# (PORT2) to get the data back, so we get the classical echo behaviour # (PORT2) to get the data back, so we get the classical echo behaviour
testserversec "$N" "$TEST" "$opts -s" "udp4-recv:$PORT1,reuseaddr!!udp4-sendto:127.0.0.1:$PORT2" "" "range=$SECONDADDR/32" "udp4-recv:$PORT2!!udp4-sendto:127.0.0.1:$PORT1" 4 udp $PORT1 0 testserversec "$N" "$TEST" "$opts -s" "udp4-sendto:127.0.0.1:$PORT2%udp4-recv:$PORT1,reuseaddr" "" "range=$SECONDADDR/32" "udp4-sendto:127.0.0.1:$PORT1%udp4-recv:$PORT2" 4 udp $PORT1 0
fi fi
esac esac
PORT=$((PORT+1)) PORT=$((PORT+1))
@ -6308,7 +6494,7 @@ $ECHO "socat: $SECONDADDR" >"$ha"
$ECHO "ALL: ALL" >"$hd" $ECHO "ALL: ALL" >"$hd"
# we use the forward channel (PORT1) for testing, and have a backward channel # we use the forward channel (PORT1) for testing, and have a backward channel
# (PORT2) to get the data back, so we get the classical echo behaviour # (PORT2) to get the data back, so we get the classical echo behaviour
testserversec "$N" "$TEST" "$opts -s" "udp4-recv:$PORT1,reuseaddr!!udp4-sendto:127.0.0.1:$PORT2" "" "tcpwrap-etc=$td" "udp4-recv:$PORT2!!udp4-sendto:127.0.0.1:$PORT1" 4 udp $PORT1 0 testserversec "$N" "$TEST" "$opts -s" "udp4-sendto:127.0.0.1:$PORT2%udp4-recv:$PORT1,reuseaddr" "" "tcpwrap-etc=$td" "udp4-sendto:127.0.0.1:$PORT1%udp4-recv:$PORT2" 4 udp $PORT1 0
fi ;; # feat fi ;; # feat
esac esac
PORT=$((PORT+1)) PORT=$((PORT+1))
@ -6390,7 +6576,7 @@ PORT2=$PORT; PORT=$((PORT+1))
PORT3=$PORT PORT3=$PORT
# we use the forward channel (PORT1) for testing, and have a backward channel # we use the forward channel (PORT1) for testing, and have a backward channel
# (PORT2) to get the data back, so we get the classical echo behaviour # (PORT2) to get the data back, so we get the classical echo behaviour
testserversec "$N" "$TEST" "$opts -s" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "sp=$PORT3" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0 testserversec "$N" "$TEST" "$opts -s" "udp6-sendto:[::1]:$PORT2%udp6-recv:$PORT1,reuseaddr" "" "sp=$PORT3" "udp6-sendto:[::1]:$PORT1%udp6-recv:$PORT2" 6 udp $PORT1 0
fi fi
esac esac
PORT=$((PORT+1)) PORT=$((PORT+1))
@ -6408,7 +6594,7 @@ PORT1=$PORT; PORT=$((PORT+1))
PORT2=$PORT PORT2=$PORT
# we use the forward channel (PORT1) for testing, and have a backward channel # we use the forward channel (PORT1) for testing, and have a backward channel
# (PORT2) to get the data back, so we get the classical echo behaviour # (PORT2) to get the data back, so we get the classical echo behaviour
testserversec "$N" "$TEST" "$opts -s" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "lowport" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0 testserversec "$N" "$TEST" "$opts -s" "udp6-sendto:[::1]:$PORT2%udp6-recv:$PORT1,reuseaddr" "" "lowport" "udp6-sendto:[::1]:$PORT1%udp6-recv:$PORT2" 6 udp $PORT1 0
fi fi
esac esac
PORT=$((PORT+1)) PORT=$((PORT+1))
@ -6426,7 +6612,7 @@ PORT1=$PORT; PORT=$((PORT+1))
PORT2=$PORT PORT2=$PORT
# we use the forward channel (PORT1) for testing, and have a backward channel # we use the forward channel (PORT1) for testing, and have a backward channel
# (PORT2) to get the data back, so we get the classical echo behaviour # (PORT2) to get the data back, so we get the classical echo behaviour
testserversec "$N" "$TEST" "$opts -s" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "range=[::2/128]" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0 testserversec "$N" "$TEST" "$opts -s" "udp6-sendto:[::1]:$PORT2%udp6-recv:$PORT1,reuseaddr" "" "range=[::2/128]" "udp6-sendto:[::1]:$PORT1%udp6-recv:$PORT2" 6 udp $PORT1 0
fi fi
esac esac
PORT=$((PORT+1)) PORT=$((PORT+1))
@ -6448,7 +6634,7 @@ PORT1=$PORT; PORT=$((PORT+1))
PORT2=$PORT PORT2=$PORT
# we use the forward channel (PORT1) for testing, and have a backward channel # we use the forward channel (PORT1) for testing, and have a backward channel
# (PORT2) to get the data back, so we get the classical echo behaviour # (PORT2) to get the data back, so we get the classical echo behaviour
testserversec "$N" "$TEST" "$opts -s" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "tcpwrap-etc=$td" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0 testserversec "$N" "$TEST" "$opts -s" "udp6-sendto:[::1]:$PORT2%udp6-recv:$PORT1,reuseaddr" "" "tcpwrap-etc=$td" "udp6-sendto:[::1]:$PORT1%udp6-recv:$PORT2" 6 udp $PORT1 0
fi ;; # feat fi ;; # feat
esac esac
PORT=$((PORT+1)) PORT=$((PORT+1))
@ -6467,7 +6653,7 @@ elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
else else
#testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr,fork" "" "range=$SECONDADDR/32" "ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0 #testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr,fork" "" "range=$SECONDADDR/32" "ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0
testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr!!udp4-sendto:127.0.0.1:$PORT" "" "range=$SECONDADDR/32" "udp4-recv:$PORT!!ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0 testserversec "$N" "$TEST" "$opts -s" "udp4-sendto:127.0.0.1:$PORT%ip4-recvfrom:$PROTO,reuseaddr" "" "range=$SECONDADDR/32" "ip4-sendto:127.0.0.1:$PROTO%udp4-recv:$PORT" 4 ip $PROTO 0
fi # not feats, not root fi # not feats, not root
esac esac
PROTO=$((PROTO+1)) PROTO=$((PROTO+1))
@ -6490,7 +6676,7 @@ hd="$td/hosts.deny"
$ECHO "socat: $SECONDADDR" >"$ha" $ECHO "socat: $SECONDADDR" >"$ha"
$ECHO "ALL: ALL" >"$hd" $ECHO "ALL: ALL" >"$hd"
#testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr,fork" "" "tcpwrap-etc=$td" "ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0 #testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr,fork" "" "tcpwrap-etc=$td" "ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0
testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr!!udp4-sendto:127.0.0.1:$PORT" "" "tcpwrap-etc=$td" "udp4-recv:$PORT!!ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0 testserversec "$N" "$TEST" "$opts -s" "udp4-sendto:127.0.0.1:$PORT%ip4-recvfrom:$PROTO,reuseaddr" "" "tcpwrap-etc=$td" "ip4-sendto:127.0.0.1:$PROTO%udp4-recv:$PORT" 4 ip $PROTO 0
fi # not feats, not root fi # not feats, not root
esac esac
PROTO=$((PROTO+1)) PROTO=$((PROTO+1))
@ -6513,7 +6699,7 @@ PROTO1=$PROTO; PROTO=$((PROTO+1))
PROTO2=$PROTO PROTO2=$PROTO
# we use the forward channel (PROTO1) for testing, and have a backward channel # we use the forward channel (PROTO1) for testing, and have a backward channel
# (PROTO2) to get the data back, so we get the classical echo behaviour # (PROTO2) to get the data back, so we get the classical echo behaviour
testserversec "$N" "$TEST" "$opts -s" "ip4-recv:$PROTO1,reuseaddr!!ip4-sendto:127.0.0.1:$PROTO2" "" "range=$SECONDADDR/32" "ip4-recv:$PROTO2!!ip4-sendto:127.0.0.1:$PROTO1" 4 ip $PROTO1 0 testserversec "$N" "$TEST" "$opts -s" "ip4-sendto:127.0.0.1:$PROTO2%ip4-recv:$PROTO1,reuseaddr" "" "range=$SECONDADDR/32" "ip4-sendto:127.0.0.1:$PROTO1%ip4-recv:$PROTO2" 4 ip $PROTO1 0
fi # not feats, not root fi # not feats, not root
esac esac
PROTO=$((PROTO+1)) PROTO=$((PROTO+1))
@ -6540,7 +6726,7 @@ $ECHO "socat: $SECONDADDR" >"$ha"
$ECHO "ALL: ALL" >"$hd" $ECHO "ALL: ALL" >"$hd"
# we use the forward channel (PROTO1) for testing, and have a backward channel # we use the forward channel (PROTO1) for testing, and have a backward channel
# (PROTO2) to get the data back, so we get the classical echo behaviour # (PROTO2) to get the data back, so we get the classical echo behaviour
testserversec "$N" "$TEST" "$opts -s" "ip4-recv:$PROTO1,reuseaddr!!ip4-sendto:127.0.0.1:$PROTO2" "" "tcpwrap-etc=$td" "ip4-recv:$PROTO2!!ip4-sendto:127.0.0.1:$PROTO1" 4 ip $PROTO1 0 testserversec "$N" "$TEST" "$opts -s" "ip4-sendto:127.0.0.1:$PROTO2%ip4-recv:$PROTO1,reuseaddr" "" "tcpwrap-etc=$td" "ip4-sendto:127.0.0.1:$PROTO1%ip4-recv:$PROTO2" 4 ip $PROTO1 0
fi # not feats, not root fi # not feats, not root
esac esac
PROTO=$((PROTO+1)) PROTO=$((PROTO+1))
@ -6559,7 +6745,7 @@ elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
else else
#testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr,fork" "" "range=[::2/128]" "ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0 #testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr,fork" "" "range=[::2/128]" "ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0
testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr!!udp6-sendto:[::1]:$PORT" "" "range=[::2/128]" "udp6-recv:$PORT!!ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0 testserversec "$N" "$TEST" "$opts -s" "udp6-sendto:[::1]:$PORT%ip6-recvfrom:$PROTO,reuseaddr" "" "range=[::2/128]" "ip6-sendto:[::1]:$PROTO%udp6-recv:$PORT" 6 ip $PROTO 0
fi # not feats, not root fi # not feats, not root
esac esac
PROTO=$((PROTO+1)) PROTO=$((PROTO+1))
@ -6582,7 +6768,7 @@ hd="$td/hosts.deny"
$ECHO "socat: [::2]" >"$ha" $ECHO "socat: [::2]" >"$ha"
$ECHO "ALL: ALL" >"$hd" $ECHO "ALL: ALL" >"$hd"
#testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr,fork" "" "tcpwrap-etc=$td" "ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0 #testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr,fork" "" "tcpwrap-etc=$td" "ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0
testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr!!udp6-sendto:[::1]:$PORT" "" "tcpwrap-etc=$td" "udp6-recv:$PORT!!ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0 testserversec "$N" "$TEST" "$opts -s" "udp6-sendto:[::1]:$PORT%ip6-recvfrom:$PROTO,reuseaddr" "" "tcpwrap-etc=$td" "ip6-sendto:[::1]:$PROTO%udp6-recv:$PORT" 6 ip $PROTO 0
fi # not feats, not root fi # not feats, not root
esac esac
PROTO=$((PROTO+1)) PROTO=$((PROTO+1))
@ -6605,7 +6791,7 @@ PROTO1=$PROTO; PROTO=$((PROTO+1))
PROTO2=$PROTO PROTO2=$PROTO
# we use the forward channel (PROTO1) for testing, and have a backward channel # we use the forward channel (PROTO1) for testing, and have a backward channel
# (PROTO2) to get the data back, so we get the classical echo behaviour # (PROTO2) to get the data back, so we get the classical echo behaviour
testserversec "$N" "$TEST" "$opts -s" "ip6-recv:$PROTO1,reuseaddr!!ip6-sendto:[::1]:$PROTO2" "" "range=[::2/128]" "ip6-recv:$PROTO2!!ip6-sendto:[::1]:$PROTO1" 6 ip $PROTO1 0 testserversec "$N" "$TEST" "$opts -s" "ip6-sendto:[::1]:$PROTO2%ip6-recv:$PROTO1,reuseaddr" "" "range=[::2/128]" "ip6-sendto:[::1]:$PROTO1%ip6-recv:$PROTO2" 6 ip $PROTO1 0
fi # not feats, not root fi # not feats, not root
esac esac
PROTO=$((PROTO+1)) PROTO=$((PROTO+1))
@ -6630,7 +6816,7 @@ $ECHO "socat: [::2]" >"$ha"
$ECHO "ALL: ALL" >"$hd" $ECHO "ALL: ALL" >"$hd"
# we use the forward channel (PROTO1) for testing, and have a backward channel # we use the forward channel (PROTO1) for testing, and have a backward channel
# (PROTO2) to get the data back, so we get the classical echo behaviour # (PROTO2) to get the data back, so we get the classical echo behaviour
testserversec "$N" "$TEST" "$opts -s" "ip6-recv:$PROTO1,reuseaddr!!ip6-sendto:[::1]:$PROTO2" "" "tcpwrap-etc=$td" "ip6-recv:$PROTO2!!ip6-sendto:[::1]:$PROTO1" 6 ip $PROTO1 0 testserversec "$N" "$TEST" "$opts -s" "ip6-sendto:[::1]:$PROTO2%ip6-recv:$PROTO1,reuseaddr" "" "tcpwrap-etc=$td" "ip6-sendto:[::1]:$PROTO1%ip6-recv:$PROTO2" 6 ip $PROTO1 0
fi # not feats, not root fi # not feats, not root
esac esac
PROTO=$((PROTO+1)) PROTO=$((PROTO+1))
@ -6836,10 +7022,27 @@ esac
N=$((N+1)) N=$((N+1))
# purpose of the shut-none option is to keep a shared socket
# open. with shared we mean that two or more processes use it. usually, when a
# process closes a socket, it performs a shutdown procedure with half close.
# on a shared socket, this would shutdown the socket as a whole, disabling it
# for all processes. the shut-none option does not shutdown but close the
# socket; this just removes the processes reference to the socket but keeps it
# open for the other processes.
NAME=TCP4ENDCLOSE NAME=TCP4ENDCLOSE
case "$TESTS" in case "$TESTS" in
*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%$NAME%*) *%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%$NAME%*)
TEST="$NAME: end-close keeps TCP V4 socket open" TEST="$NAME: shut-none keeps TCP V4 socket open"
# this is how we test the shut-none option:
# we have some tcp service (CMD3) that accepts one connection and only receives
# date.
# a multiplexer process (CMD) opens a connection to that service; it accepts
# multiple connections from client processes and merges and forwards their
# data; each client is handled in a sub process with a clone of the forwarder
# socket.
# two client processes connect and send data. normally, the "common" connection
# would terminate when the first client disconnects; with the shut-none option,
# the data of the second process also has to arrive at the target service.
tf="$td/test$N.stdout" tf="$td/test$N.stdout"
te="$td/test$N.stderr" te="$td/test$N.stderr"
tdiff="$td/test$N.diff" tdiff="$td/test$N.diff"
@ -6848,7 +7051,7 @@ p2=$PORT
da1a="$(date) $RANDOM" da1a="$(date) $RANDOM"
da1b="$(date) $RANDOM" da1b="$(date) $RANDOM"
CMD1="$SOCAT $opts -u - TCP4-CONNECT:$LOCALHOST:$p1" CMD1="$SOCAT $opts -u - TCP4-CONNECT:$LOCALHOST:$p1"
CMD="$SOCAT $opts -U TCP4:$LOCALHOST:$p2,end-close TCP4-LISTEN:$p1,bind=$LOCALHOST,reuseaddr,fork" CMD="$SOCAT $opts -U TCP4:$LOCALHOST:$p2,shut-none TCP4-LISTEN:$p1,bind=$LOCALHOST,reuseaddr,fork"
CMD3="$SOCAT $opts -u TCP4-LISTEN:$p2,reuseaddr,bind=$LOCALHOST -" CMD3="$SOCAT $opts -u TCP4-LISTEN:$p2,reuseaddr,bind=$LOCALHOST -"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD3 >"$tf" 2>"${te}3" & $CMD3 >"$tf" 2>"${te}3" &
@ -6882,11 +7085,21 @@ esac
PORT=$((PORT+1)) PORT=$((PORT+1))
N=$((N+1)) N=$((N+1))
# purpose: see above; here we do not test against a TCP socket but an exec'd
# sub process (socketpair)
NAME=EXECENDCLOSE NAME=EXECENDCLOSE
case "$TESTS" in case "$TESTS" in
*%functions%*|*%exec%*|*%$NAME%*) *%functions%*|*%exec%*|*%$NAME%*)
TEST="$NAME: end-close keeps EXEC child running" TEST="$NAME: shut-none keeps EXEC child running"
# this is how we test the shut-none option:
# we have a server process (CMD) that runs a program (cat); the process accepts
# multiple connections from client processes and merges and forwards their
# data; each client is handled in a sub process with a clone of the forwarder
# socket.
# two client processes connect and send data. normally, the "common" connection
# the the cat sub process would terminate when the first client disconnects;
# with the shut-none option, the data of the second process also has to arrive
# at the target service.
tf="$td/test$N.stdout" tf="$td/test$N.stdout"
te="$td/test$N.stderr" te="$td/test$N.stderr"
ts="$td/test$N.sock" ts="$td/test$N.sock"
@ -6894,7 +7107,7 @@ tdiff="$td/test$N.diff"
da1a="$(date) $RANDOM" da1a="$(date) $RANDOM"
da1b="$(date) $RANDOM" da1b="$(date) $RANDOM"
CMD1="$SOCAT $opts - UNIX-CONNECT:$ts" CMD1="$SOCAT $opts - UNIX-CONNECT:$ts"
CMD="$SOCAT -t0.1 $opts EXEC:"$CAT",end-close UNIX-LISTEN:$ts,fork" CMD="$SOCAT -t0.1 $opts EXEC:"$CAT",shut-none,end-close UNIX-LISTEN:$ts,fork"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD 2>"${te}2" & $CMD 2>"${te}2" &
pid2=$! pid2=$!
@ -6906,16 +7119,18 @@ usleep 100000
kill "$pid2" 2>/dev/null kill "$pid2" 2>/dev/null
wait wait
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n" $PRINTF "$FAILED\n"
echo "$CMD1 &" echo "$CMD1 &"
echo "$CMD2" echo "$CMD"
cat "${te}1a" "${te}1b" "${te}2" cat "${te}1a" "${te}1b" "${te}2"
$PRINTF "$FAILED: $SOCAT:\n" numFAIL=$((numFAIL+1))
elif ! echo -e "$da1a\n$da1b" |diff - "$tf" >"$tdiff"; then elif ! echo -e "$da1a\n$da1b" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED\n" $PRINTF "$FAILED\n"
echo "$CMD1 &"
echo "$CMD"
cat "$tdiff" cat "$tdiff"
cat "${te}1a" "${te}1b" "${te}2" cat "${te}1a" "${te}1b" "${te}2"
$PRINTF "$FAILED: $SOCAT:\n" numFAIL=$((numFAIL+1))
else else
$PRINTF "$OK\n" $PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}1a" "${te}1b" "${te}2"; fi if [ -n "$debug" ]; then cat "${te}1a" "${te}1b" "${te}2"; fi
@ -7721,7 +7936,7 @@ to="$td/test$N.out"
te="$td/test$N.err" te="$td/test$N.err"
tdiff="$td/test$N.diff" tdiff="$td/test$N.diff"
da="$(date)" da="$da$($ECHO '\r')" da="$(date)" da="$da$($ECHO '\r')"
CMD="$SOCAT $opts system:\"echo A; sleep 2\",readbytes=2!!- -!!/dev/null" CMD="$SOCAT $opts -%system:\"echo A; sleep 2\",readbytes=2 /dev/null%-"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
(sleep 1; echo) |eval "$CMD" >"$to" 2>"$te" (sleep 1; echo) |eval "$CMD" >"$to" 2>"$te"
if test -s "$to"; then if test -s "$to"; then

View file

@ -1,5 +1,5 @@
/* $Id: xio-creat.c,v 1.16 2006/07/13 06:39:01 gerhard Exp $ */ /* $Id: xio-creat.c,v 1.16.2.1 2006/07/24 19:17:32 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of create type */ /* this file contains the source for opening addresses of create type */
@ -17,8 +17,11 @@ static int xioopen_creat(int arg, const char *argv[], struct opt *opts, int rw,
/*! within stream model, this is a write-only address - use 2 instead of 3 */ /*! within stream model, this is a write-only address - use 2 instead of 3 */
const struct addrdesc addr_creat = { "create", 3, xioopen_creat, GROUP_FD|GROUP_NAMED|GROUP_FILE, 0, 0, 0 HELP(":<filename>") }; static const struct xioaddr_endpoint_desc xioaddr_creat1 = { XIOADDR_SYS, "create", 1, XIOBIT_ALL/*?*/, GROUP_FD|GROUP_NAMED|GROUP_FILE, XIOSHUT_NONE, XIOCLOSE_CLOSE, xioopen_creat, 0, 0, 0 HELP(":<filename>") };
const union xioaddr_desc *xioaddrs_creat[] = {
(union xioaddr_desc *)&xioaddr_creat1,
NULL
};
/* retrieve the mode option and perform the creat() call. /* retrieve the mode option and perform the creat() call.
returns the file descriptor or a negative value. */ returns the file descriptor or a negative value. */
@ -60,15 +63,16 @@ static int xioopen_creat(int argc, const char *argv[], struct opt *opts, int xio
Notice2("creating regular file \"%s\" for %s", filename, ddirection[rw]); Notice2("creating regular file \"%s\" for %s", filename, ddirection[rw]);
if ((result = _xioopen_creat(filename, rw, opts)) < 0) if ((result = _xioopen_creat(filename, rw, opts)) < 0)
return result; return result;
fd->stream.fd = result; fd->stream.fd1 = fd->stream.fd2 = result;
fd->stream.fdtype = FDTYPE_SINGLE;
applyopts_named(filename, opts, PH_PASTOPEN); applyopts_named(filename, opts, PH_PASTOPEN);
if ((result = applyopts2(fd->stream.fd, opts, PH_PASTOPEN, PH_LATE2)) < 0) if ((result = applyopts2(fd->stream.fd1, opts, PH_PASTOPEN, PH_LATE2)) < 0)
return result; return result;
applyopts_cloexec(fd->stream.fd, opts); applyopts_cloexec(fd->stream.fd1, opts);
applyopts_fchown(fd->stream.fd, opts); applyopts_fchown(fd->stream.fd1, opts);
if ((result = _xio_openlate(&fd->stream, opts)) < 0) if ((result = _xio_openlate(&fd->stream, opts)) < 0)
return result; return result;

View file

@ -1,10 +1,10 @@
/* $Id: xio-creat.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */ /* $Id: xio-creat.h,v 1.4.2.1 2006/07/24 19:17:34 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_creat_h_included #ifndef __xio_creat_h_included
#define __xio_creat_h_included 1 #define __xio_creat_h_included 1
extern const struct addrdesc addr_creat; extern const union xioaddr_desc *xioaddrs_creat[];
#endif /* !defined(__xio_creat_h_included) */ #endif /* !defined(__xio_creat_h_included) */

View file

@ -1,8 +1,11 @@
/* $Id: xio-exec.c,v 1.19 2006/07/12 21:59:28 gerhard Exp $ */ /* $Id: xio-exec.c,v 1.19.2.1 2006/07/24 19:17:35 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of exec type */ /* this file contains the source for opening addresses of exec type */
/* this file contains the source for an inter address that just invokes a
program. The program should provide its data side on FDs 0 and 1, and its
protocol side on FDs 3 and 4. */
#include "xiosysincludes.h" #include "xiosysincludes.h"
#include "xioopen.h" #include "xioopen.h"
@ -13,18 +16,25 @@
#if WITH_EXEC #if WITH_EXEC
static int xioopen_exec(int argc, const char *argv[], struct opt *opts, static int xioopen_exec1end(int argc, const char *argv[], struct opt *opts,
int xioflags, /* XIO_RDONLY etc. */ int xioflags, /* XIO_RDONLY etc. */
xiofile_t *fd, xiofile_t *fd,
unsigned groups, unsigned groups,
int dummy1, int dummy2, int dummy3 int dummy1, int dummy2, int dummy3
); );
const struct addrdesc addr_exec = { "exec", 3, xioopen_exec, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, 0, 0, 0 HELP(":<command-line>") };
static const struct xioaddr_endpoint_desc xioaddr_exec1end = { XIOADDR_ENDPOINT, "exec", 1, XIOBIT_ALL, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_exec1end, 0, 0, 0 HELP(":<command-line>") };
const union xioaddr_desc *xioaddrs_exec[] = {
(union xioaddr_desc *)&xioaddr_exec1end,
NULL };
const struct optdesc opt_dash = { "dash", "login", OPT_DASH, GROUP_EXEC, PH_PREEXEC, TYPE_BOOL, OFUNC_SPEC }; const struct optdesc opt_dash = { "dash", "login", OPT_DASH, GROUP_EXEC, PH_PREEXEC, TYPE_BOOL, OFUNC_SPEC };
static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
static int xioopen_exec1end(int argc, const char *argv[], struct opt *opts,
int xioflags, /* XIO_RDONLY, XIO_MAYCHILD etc. */ int xioflags, /* XIO_RDONLY, XIO_MAYCHILD etc. */
xiofile_t *fd, xiofile_t *fd,
unsigned groups, unsigned groups,
@ -39,7 +49,7 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
retropt_bool(opts, OPT_DASH, &dash); retropt_bool(opts, OPT_DASH, &dash);
status = _xioopen_foxec(xioflags, &fd->stream, groups, &opts); status = _xioopen_foxec_end(xioflags, &fd->stream, groups, &opts);
if (status < 0) return status; if (status < 0) return status;
if (status == 0) { /* child */ if (status == 0) { /* child */
const char *ends[] = { " ", NULL }; const char *ends[] = { " ", NULL };
@ -74,7 +84,7 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
token = Malloc(len); /*! */ token = Malloc(len); /*! */
tokp = token; tokp = token;
if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests, if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
true, true, false) < 0) { false, true, true, false) < 0) {
Error("internal: miscalculated string lengths"); Error("internal: miscalculated string lengths");
} }
*tokp++ = '\0'; *tokp++ = '\0';
@ -89,7 +99,7 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
++strp; ++strp;
pargv[pargc++] = tokp; pargv[pargc++] = tokp;
if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests, if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
true, true, false) < 0) { false, true, true, false) < 0) {
Error("internal: miscalculated string lengths"); Error("internal: miscalculated string lengths");
} }
*tokp++ = '\0'; *tokp++ = '\0';
@ -134,4 +144,5 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
/* parent */ /* parent */
return 0; return 0;
} }
#endif /* WITH_EXEC */ #endif /* WITH_EXEC */

View file

@ -1,11 +1,11 @@
/* $Id: xio-exec.h,v 1.6 2002/05/19 08:05:36 gerhard Exp $ */ /* $Id: xio-exec.h,v 1.6.2.1 2006/07/24 19:17:37 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001, 2002 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_exec_h_included #ifndef __xio_exec_h_included
#define __xio_exec_h_included 1 #define __xio_exec_h_included 1
extern const struct addrdesc addr_exec; extern const union xioaddr_desc *xioaddrs_exec[];
extern const struct optdesc opt_dash; extern const struct optdesc opt_dash;

View file

@ -1,5 +1,5 @@
/* $Id: xio-fd.c,v 1.26 2006/12/28 07:35:50 gerhard Exp $ */ /* $Id: xio-fd.c,v 1.26 2006/12/28 07:35:50 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains common file descriptor related option definitions */ /* this file contains common file descriptor related option definitions */
@ -74,4 +74,5 @@ const struct optdesc opt_flock_ex_nb = { "flock-ex-nb", "flock-nb", OPT_FLOCK_E
const struct optdesc opt_cool_write = { "cool-write", "coolwrite", OPT_COOL_WRITE, GROUP_FD, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.cool_write }; const struct optdesc opt_cool_write = { "cool-write", "coolwrite", OPT_COOL_WRITE, GROUP_FD, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.cool_write };
/* control closing of connections */ /* control closing of connections */
const struct optdesc opt_end_close = { "end-close", "close", OPT_END_CLOSE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoend, END_CLOSE }; const struct optdesc opt_end_close = { "end-close", NULL, OPT_END_CLOSE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoclose, XIOCLOSE_CLOSE };
const struct optdesc opt_shut_none = { "shut-none", NULL, OPT_SHUT_NONE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoshut, XIOSHUT_NONE };

View file

@ -1,5 +1,5 @@
/* $Id: xio-fd.h,v 1.12 2006/12/28 07:35:50 gerhard Exp $ */ /* $Id: xio-fd.h,v 1.12 2006/12/28 07:35:50 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_fd_h_included #ifndef __xio_fd_h_included
@ -37,5 +37,6 @@ extern const struct optdesc opt_f_setlk_wr;
extern const struct optdesc opt_f_setlkw_wr; extern const struct optdesc opt_f_setlkw_wr;
extern const struct optdesc opt_cool_write; extern const struct optdesc opt_cool_write;
extern const struct optdesc opt_end_close; extern const struct optdesc opt_end_close;
extern const struct optdesc opt_shut_none;
#endif /* !defined(__xio_fd_h_included) */ #endif /* !defined(__xio_fd_h_included) */

View file

@ -1,5 +1,5 @@
/* $Id: xio-fdnum.c,v 1.13 2006/07/08 10:03:14 gerhard Exp $ */ /* $Id: xio-fdnum.c,v 1.13.2.1 2006/07/24 19:17:38 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of fdnum type */ /* this file contains the source for opening addresses of fdnum type */
@ -15,8 +15,13 @@
static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts, int rw, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3); static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts, int rw, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3);
const struct addrdesc addr_fd = { "fd", 3, xioopen_fdnum, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 0, 0, 0 HELP(":<num>") }; const struct xioaddr_endpoint_desc xioaddr_fdnum1 = { XIOADDR_ENDPOINT, "fd", 1, XIOBIT_ALL, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_fdnum, 0, 0, 0 HELP(":<num>") };
const struct xioaddr_endpoint_desc xioaddr_fdnum2 = { XIOADDR_ENDPOINT, "fd", 2, XIOBIT_RDWR, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_fdnum, 0, 0, 0 HELP(":<numout>:<numin>") };
const union xioaddr_desc *xioaddrs_fdnum[] = {
(union xioaddr_desc *)&xioaddr_fdnum1,
(union xioaddr_desc *)&xioaddr_fdnum2,
NULL };
/* use some file descriptor and apply the options. Set the FD_CLOEXEC flag. */ /* use some file descriptor and apply the options. Set the FD_CLOEXEC flag. */
static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts, static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts,
@ -24,23 +29,43 @@ static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts,
int dummy1, int dummy2, int dummy3) { int dummy1, int dummy2, int dummy3) {
char *a1; char *a1;
int rw = (xioflags&XIO_ACCMODE); int rw = (xioflags&XIO_ACCMODE);
int numfd; int numfd1, numfd2 = -1;
int result; int result;
if (argc != 2) { if (argc < 2 || argc > 3) {
Error3("%s:%s: wrong number of parameters (%d instead of 1)", argv[0], argv[1], argc-1); Error3("%s:%s: wrong number of parameters (%d instead of 1 or 2)", argv[0], argv[1], argc-1);
} }
numfd = strtoul(argv[1], &a1, 0); numfd1 = strtoul(argv[1], &a1, 0);
if (*a1 != '\0') { if (*a1 != '\0') {
Error1("error in FD number \"%s\"", argv[1]); Error1("error in FD number \"%s\"", argv[1]);
} }
/* we dont want to see these fds in child processes */ /* we dont want to see these fds in child processes */
if (Fcntl_l(numfd, F_SETFD, FD_CLOEXEC) < 0) { if (Fcntl_l(numfd1, F_SETFD, FD_CLOEXEC) < 0) {
Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", numfd, strerror(errno)); Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", numfd1, strerror(errno));
} }
Notice2("using file descriptor %d for %s", numfd, ddirection[rw]);
if ((result = xioopen_fd(opts, rw, &xfd->stream, numfd, dummy2, dummy3)) < 0) { if (argv[2]) {
if (rw != XIO_RDWR) {
Warn("two file descriptors given for unidirectional transfer");
}
numfd2 = numfd1;
numfd1 = strtoul(argv[2], &a1, 0);
if (*a1 != '\0') {
Error1("error in FD number \"%s\"", argv[2]);
}
/* we dont want to see these fds in child processes */
if (Fcntl_l(numfd2, F_SETFD, FD_CLOEXEC) < 0) {
Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", numfd2, strerror(errno));
}
}
if (argv[2] == NULL) {
Notice2("using file descriptor %d for %s", numfd1, ddirection[rw]);
} else {
Notice4("using file descriptors %d for %s and %d for %s", numfd1, ddirection[((rw+1)&1)-1], numfd2, ddirection[((rw+1)&2)-1]);
}
if ((result = xioopen_fd(opts, rw, xfd, numfd1, numfd2, dummy2, dummy3)) < 0) {
return result; return result;
} }
return 0; return 0;
@ -52,27 +77,32 @@ static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts,
/* retrieve and apply options to a standard file descriptor. /* retrieve and apply options to a standard file descriptor.
Do not set FD_CLOEXEC flag. */ Do not set FD_CLOEXEC flag. */
int xioopen_fd(struct opt *opts, int rw, xiosingle_t *xfd, int numfd, int dummy2, int dummy3) { int xioopen_fd(struct opt *opts, int rw, xiofile_t *xfd, int numfd1, int numfd2, int dummy2, int dummy3) {
xfd->fd = numfd; xfd->stream.fd1 = numfd1;
xfd->howtoend = END_NONE; xfd->stream.fd2 = numfd2;
if (numfd2 >= 0) {
xfd->stream.fdtype = FDTYPE_DOUBLE;
} else {
xfd->stream.fdtype = FDTYPE_SINGLE;
}
#if WITH_TERMIOS #if WITH_TERMIOS
if (Isatty(xfd->fd)) { if (Isatty(xfd->stream.fd1)) {
if (Tcgetattr(xfd->fd, &xfd->savetty) < 0) { if (Tcgetattr(xfd->stream.fd1, &xfd->stream.savetty) < 0) {
Warn2("cannot query current terminal settings on fd %d: %s", Warn2("cannot query current terminal settings on fd %d: %s",
xfd->fd, strerror(errno)); xfd->stream.fd1, strerror(errno));
} else { } else {
xfd->ttyvalid = true; xfd->stream.ttyvalid = true;
} }
} }
#endif /* WITH_TERMIOS */ #endif /* WITH_TERMIOS */
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
applyopts2(xfd->fd, opts, PH_INIT, PH_FD); applyopts2(xfd->stream.fd1, opts, PH_INIT, PH_FD);
return _xio_openlate(xfd, opts); return _xio_openlate(&xfd->stream, opts);
} }
#endif /* WITH_FD */ #endif /* WITH_FD */

View file

@ -1,12 +1,13 @@
/* $Id: xio-fdnum.h,v 1.6 2006/03/21 20:48:31 gerhard Exp $ */ /* $Id: xio-fdnum.h,v 1.6.2.1 2006/07/24 19:17:40 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_fdnum_h_included #ifndef __xio_fdnum_h_included
#define __xio_fdnum_h_included 1 #define __xio_fdnum_h_included 1
extern const struct addrdesc addr_fd; extern const struct xioaddr_endpoint_desc xioaddr_fdnum1;
extern const union xioaddr_desc *xioaddrs_fdnum[];
extern int xioopen_fd(struct opt *opts, int rw, xiosingle_t *xfd, int numfd, int dummy2, int dummy3); extern int xioopen_fd(struct opt *opts, int rw, xiofile_t *xfd, int numfd1, int numfd2, int dummy2, int dummy3);
#endif /* !defined(__xio_fdnum_h_included) */ #endif /* !defined(__xio_fdnum_h_included) */

View file

@ -11,7 +11,7 @@
#include "xio-file.h" #include "xio-file.h"
static int xioopen_open(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); static int xioopen_open1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
#if WITH_OPEN #if WITH_OPEN
@ -66,13 +66,17 @@ const struct optdesc opt_o_trunc = { "o-trunc", "trunc", OPT_O_TRUNC,
#if _WITH_FILE /*! inconsistent name FILE vs. OPEN */ #if _WITH_FILE /*! inconsistent name FILE vs. OPEN */
const struct addrdesc addr_open = { "open", 3, xioopen_open, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS, 0, 0, 0 HELP(":<filename>") }; static const struct xioaddr_endpoint_desc xioaddr_open1 = { XIOADDR_SYS, "open", 1, XIOBIT_ALL, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS, XIOSHUT_CLOSE, XIOCLOSE_CLOSE, xioopen_open1, 0, 0, 0 HELP(":<filename>") };
const union xioaddr_desc *xioaddrs_open[] = {
(union xioaddr_desc *)&xioaddr_open1,
NULL
};
/* open for writing: /* open for writing:
if the filesystem entry already exists, the data is appended if the filesystem entry already exists, the data is appended
if it does not exist, a file is created and the data is appended if it does not exist, a file is created and the data is appended
*/ */
static int xioopen_open(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) { static int xioopen_open1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) {
const char *filename = argv[1]; const char *filename = argv[1];
int rw = (xioflags & XIO_ACCMODE); int rw = (xioflags & XIO_ACCMODE);
bool exists; bool exists;
@ -96,13 +100,14 @@ static int xioopen_open(int argc, const char *argv[], struct opt *opts, int xiof
filetypenames[(result&S_IFMT)>>12], filename, ddirection[rw]); filetypenames[(result&S_IFMT)>>12], filename, ddirection[rw]);
if ((result = _xioopen_open(filename, rw, opts)) < 0) if ((result = _xioopen_open(filename, rw, opts)) < 0)
return result; return result;
fd->stream.fd = result; fd->stream.fd1 = result;
fd->stream.fdtype = FDTYPE_SINGLE;
#if WITH_TERMIOS #if WITH_TERMIOS
if (Isatty(fd->stream.fd)) { if (Isatty(fd->stream.fd1)) {
if (Tcgetattr(fd->stream.fd, &fd->stream.savetty) < 0) { if (Tcgetattr(fd->stream.fd1, &fd->stream.savetty) < 0) {
Warn2("cannot query current terminal settings on fd %d: %s", Warn2("cannot query current terminal settings on fd %d: %s",
fd->stream.fd, strerror(errno)); fd->stream.fd1, strerror(errno));
} else { } else {
fd->stream.ttyvalid = true; fd->stream.ttyvalid = true;
} }
@ -110,10 +115,10 @@ static int xioopen_open(int argc, const char *argv[], struct opt *opts, int xiof
#endif /* WITH_TERMIOS */ #endif /* WITH_TERMIOS */
applyopts_named(filename, opts, PH_FD); applyopts_named(filename, opts, PH_FD);
applyopts(fd->stream.fd, opts, PH_FD); applyopts(fd->stream.fd1, opts, PH_FD);
applyopts_cloexec(fd->stream.fd, opts); applyopts_cloexec(fd->stream.fd1, opts);
applyopts_fchown(fd->stream.fd, opts); applyopts_fchown(fd->stream.fd1, opts);
if ((result = _xio_openlate(&fd->stream, opts)) < 0) if ((result = _xio_openlate(&fd->stream, opts)) < 0)
return result; return result;

View file

@ -1,5 +1,5 @@
/* $Id: xio-file.h,v 1.8 2006/07/13 21:19:15 gerhard Exp $ */ /* $Id: xio-file.h,v 1.8.2.1 2006/07/24 19:17:44 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_file_h_included #ifndef __xio_file_h_included
@ -26,6 +26,6 @@ extern const struct optdesc opt_o_priv;
extern const struct optdesc opt_o_trunc; extern const struct optdesc opt_o_trunc;
extern const struct optdesc opt_o_noatime; extern const struct optdesc opt_o_noatime;
extern const struct addrdesc addr_open; extern const union xioaddr_desc *xioaddrs_open[];
#endif /* !defined(__xio_file_h_included) */ #endif /* !defined(__xio_file_h_included) */

View file

@ -14,12 +14,17 @@
#if WITH_GOPEN #if WITH_GOPEN
static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); static int xioopen_gopen1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
const struct addrdesc addr_gopen = { "gopen", 3, xioopen_gopen, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS|GROUP_SOCKET|GROUP_SOCK_UNIX, 0, 0, 0 HELP(":<filename>") }; const struct xioaddr_endpoint_desc xioaddr_gopen1 = { XIOADDR_SYS, "gopen", 1, XIOBIT_ALL, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS|GROUP_SOCKET|GROUP_SOCK_UNIX, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_gopen1, 0, 0, 0 HELP(":<filename>") };
static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) { const union xioaddr_desc *xioaddrs_gopen[] = {
(union xioaddr_desc *)&xioaddr_gopen1,
NULL
};
static int xioopen_gopen1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) {
const char *filename = argv[1]; const char *filename = argv[1];
flags_t openflags = (xioflags & XIO_ACCMODE); flags_t openflags = (xioflags & XIO_ACCMODE);
mode_t st_mode; mode_t st_mode;
@ -76,24 +81,30 @@ static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xio
/* save options, because we might have to start again with Socket() */ /* save options, because we might have to start again with Socket() */
opts2 = copyopts(opts, GROUP_ALL); opts2 = copyopts(opts, GROUP_ALL);
if ((fd->stream.fd = Socket(PF_UNIX, socktype, 0)) < 0) { if ((fd->stream.fd1 = Socket(PF_UNIX, socktype, 0)) < 0) {
Error2("socket(PF_UNIX, %d, 0): %s", socktype, strerror(errno)); Error2("socket(PF_UNIX, %d, 0): %s", socktype, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
/*0 Info2("socket(PF_UNIX, %d, 0) -> %d", socktype, fd->stream.fd);*/ fd->stream.fd2 = fd->stream.fd1;
applyopts(fd->stream.fd, opts, PH_PASTSOCKET); fd->stream.fdtype = FDTYPE_SINGLE;
applyopts(fd->stream.fd, opts, PH_FD); if (fd->stream.howtoshut == XIOSHUT_UNSPEC)
fd->stream.howtoshut = XIOSHUT_DOWN;
if (fd->stream.howtoclose == XIOCLOSE_UNSPEC)
fd->stream.howtoclose = XIOCLOSE_CLOSE;
/*0 Info2("socket(PF_UNIX, %d, 0) -> %d", socktype, fd->stream.fd1);*/
applyopts(fd->stream.fd1, opts, PH_PASTSOCKET);
applyopts(fd->stream.fd1, opts, PH_FD);
applyopts_cloexec(fd->stream.fd, opts); applyopts_cloexec(fd->stream.fd1, opts);
sa.sun_family = AF_UNIX; sa.sun_family = AF_UNIX;
salen = xiosetunix(&sa, filename, false, false); salen = xiosetunix(&sa, filename, false, false);
#if 0 #if 0
applyopts(fd->stream.fd, opts, PH_PREBIND); applyopts(fd->stream.fd1, opts, PH_PREBIND);
applyopts(fd->stream.fd, opts, PH_BIND); applyopts(fd->stream.fd1, opts, PH_BIND);
if (us) { if (us) {
if (Bind(fd->stream.fd, us, uslen) < 0) { if (Bind(fd->stream.fd1, us, uslen) < 0) {
Error4("bind(%d, {%s}, "F_Zd"): %s", Error4("bind(%d, {%s}, "F_Zd"): %s",
fd->fd, sockaddr_info(us, infobuff, sizeof(infobuff)), fd->fd, sockaddr_info(us, infobuff, sizeof(infobuff)),
uslen, strerror(errno)); uslen, strerror(errno));
@ -104,33 +115,33 @@ static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xio
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} }
applyopts(fd->stream.fd, opts, PH_PASTBIND); applyopts(fd->stream.fd1, opts, PH_PASTBIND);
#endif /* 0 */ #endif /* 0 */
applyopts(fd->stream.fd, opts, PH_CONNECT); applyopts(fd->stream.fd1, opts, PH_CONNECT);
if ((result = Connect(fd->stream.fd, (struct sockaddr *)&sa, salen)) < 0) { if ((result = Connect(fd->stream.fd1, (struct sockaddr *)&sa, salen)) < 0) {
if (errno == EINPROGRESS) { if (errno == EINPROGRESS) {
Warn4("connect(%d, %s, "F_Zd"): %s", Warn4("connect(%d, %s, "F_Zd"): %s",
fd->stream.fd, sockaddr_unix_info(&sa, salen, infobuff, sizeof(infobuff)), fd->stream.fd1, sockaddr_unix_info(&sa, salen, infobuff, sizeof(infobuff)),
sizeof(sa), strerror(errno)); sizeof(sa), strerror(errno));
} else if (errno == EPROTOTYPE && optsotype != SOCK_STREAM) { } else if (errno == EPROTOTYPE && optsotype != SOCK_STREAM) {
Warn4("connect(%d, %s, "F_Zd"): %s", Warn4("connect(%d, %s, "F_Zd"): %s",
fd->stream.fd, sockaddr_unix_info(&sa, salen, infobuff, sizeof(infobuff)), fd->stream.fd1, sockaddr_unix_info(&sa, salen, infobuff, sizeof(infobuff)),
sizeof(sa), strerror(errno)); sizeof(sa), strerror(errno));
Info("assuming datagram socket"); Info("assuming datagram socket");
Close(fd->stream.fd); Close(fd->stream.fd1);
opts = opts2; opts = opts2;
if ((fd->stream.fd = Socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) { if ((fd->stream.fd1 = Socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
Error1("socket(PF_UNIX, SOCK_DGRAM, 0): %s", strerror(errno)); Error1("socket(PF_UNIX, SOCK_DGRAM, 0): %s", strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
/*0 Info1("socket(PF_UNIX, SOCK_DGRAM, 0) -> %d", fd->stream.fd);*/ /*0 Info1("socket(PF_UNIX, SOCK_DGRAM, 0) -> %d", fd->stream.fd1);*/
applyopts(fd->stream.fd, opts, PH_PASTSOCKET); applyopts(fd->stream.fd1, opts, PH_PASTSOCKET);
applyopts(fd->stream.fd, opts, PH_FD); applyopts(fd->stream.fd1, opts, PH_FD);
applyopts_cloexec(fd->stream.fd, opts); applyopts_cloexec(fd->stream.fd1, opts);
sa.sun_family = AF_UNIX; sa.sun_family = AF_UNIX;
strncpy(sa.sun_path, filename, sizeof(sa.sun_path)); strncpy(sa.sun_path, filename, sizeof(sa.sun_path));
@ -140,23 +151,24 @@ static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xio
memcpy(&fd->stream.peersa.soa, &sa, fd->stream.salen); memcpy(&fd->stream.peersa.soa, &sa, fd->stream.salen);
} else { } else {
Error4("connect(%d, %s, "F_Zd"): %s", Error4("connect(%d, %s, "F_Zd"): %s",
fd->stream.fd, sockaddr_unix_info(&sa, fd->stream.salen, infobuff, sizeof(infobuff)), fd->stream.fd1, sockaddr_unix_info(&sa, fd->stream.salen, infobuff, sizeof(infobuff)),
sizeof(sa), strerror(errno)); sizeof(sa), strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} }
if (fd->stream.howtoend == END_UNSPEC) { if (fd->stream.howtoshut == XIOSHUT_UNSPEC)
fd->stream.howtoend = END_SHUTDOWN; fd->stream.howtoshut = XIOSHUT_CLOSE;
} if (fd->stream.howtoclose == XIOCLOSE_UNSPEC)
fd->stream.howtoclose = XIOCLOSE_CLOSE;
applyopts_fchown(fd->stream.fd, opts); applyopts_fchown(fd->stream.fd1, opts);
applyopts(fd->stream.fd, opts, PH_CONNECTED); applyopts(fd->stream.fd1, opts, PH_CONNECTED);
applyopts(fd->stream.fd, opts, PH_LATE); applyopts(fd->stream.fd1, opts, PH_LATE);
applyopts_named(filename, opts, PH_PASTOPEN); /* unlink-late */ applyopts_named(filename, opts, PH_PASTOPEN); /* unlink-late */
if (Getsockname(fd->stream.fd, (struct sockaddr *)&us, &uslen) < 0) { if (Getsockname(fd->stream.fd1, (struct sockaddr *)&us, &uslen) < 0) {
Warn4("getsockname(%d, %p, {%d}): %s", Warn4("getsockname(%d, %p, {%d}): %s",
fd->stream.fd, &us, uslen, strerror(errno)); fd->stream.fd1, &us, uslen, strerror(errno));
} else { } else {
Notice1("successfully connected via %s", Notice1("successfully connected via %s",
sockaddr_unix_info(&us, uslen, infobuff, sizeof(infobuff))); sockaddr_unix_info(&us, uslen, infobuff, sizeof(infobuff)));
@ -190,24 +202,28 @@ static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xio
Ioctl(result, I_PUSH, "ttcompat"); Ioctl(result, I_PUSH, "ttcompat");
} }
#endif #endif
fd->stream.fd = result; if (fd->stream.howtoshut == XIOSHUT_UNSPEC)
fd->stream.howtoshut = XIOSHUT_NONE;
if (fd->stream.howtoclose == XIOCLOSE_UNSPEC)
fd->stream.howtoclose = XIOCLOSE_CLOSE;
fd->stream.fd1 = result;
#if WITH_TERMIOS #if WITH_TERMIOS
if (Isatty(fd->stream.fd)) { if (Isatty(fd->stream.fd1)) {
if (Tcgetattr(fd->stream.fd, &fd->stream.savetty) < 0) { if (Tcgetattr(fd->stream.fd1, &fd->stream.savetty) < 0) {
Warn2("cannot query current terminal settings on fd %d: %s", Warn2("cannot query current terminal settings on fd %d: %s",
fd->stream.fd, strerror(errno)); fd->stream.fd1, strerror(errno));
} else { } else {
fd->stream.ttyvalid = true; fd->stream.ttyvalid = true;
} }
} }
#endif /* WITH_TERMIOS */ #endif /* WITH_TERMIOS */
applyopts_named(filename, opts, PH_FD); applyopts_named(filename, opts, PH_FD);
applyopts(fd->stream.fd, opts, PH_FD); applyopts(fd->stream.fd1, opts, PH_FD);
applyopts_cloexec(fd->stream.fd, opts); applyopts_cloexec(fd->stream.fd1, opts);
} }
if ((result = applyopts2(fd->stream.fd, opts, PH_PASTSOCKET, PH_CONNECTED)) < 0) if ((result = applyopts2(fd->stream.fd1, opts, PH_PASTSOCKET, PH_CONNECTED)) < 0)
return result; return result;
if ((result = _xio_openlate(&fd->stream, opts)) < 0) if ((result = _xio_openlate(&fd->stream, opts)) < 0)

View file

@ -1,10 +1,11 @@
/* $Id: xio-gopen.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */ /* $Id: xio-gopen.h,v 1.4.2.1 2006/07/24 19:17:49 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_gopen_h_included #ifndef __xio_gopen_h_included
#define __xio_gopen_h_included 1 #define __xio_gopen_h_included 1
extern const struct addrdesc addr_gopen; extern const struct xioaddr_endpoint_desc xioaddr_gopen1;
extern const union xioaddr_desc *xioaddrs_gopen[];
#endif /* !defined(__xio_gopen_h_included) */ #endif /* !defined(__xio_gopen_h_included) */

View file

@ -6,7 +6,7 @@
#include "xiosysincludes.h" #include "xiosysincludes.h"
#if WITH_TCP || WITH_UDP #if _WITH_TCP || _WITH_UDP
#include "xioopen.h" #include "xioopen.h"
#include "xio-socket.h" #include "xio-socket.h"
@ -19,7 +19,7 @@ const struct optdesc opt_sourceport = { "sourceport", "sp", OPT_SOURCEPORT
/*const struct optdesc opt_port = { "port", NULL, OPT_PORT, GROUP_IPAPP, PH_BIND, TYPE_USHORT, OFUNC_SPEC };*/ /*const struct optdesc opt_port = { "port", NULL, OPT_PORT, GROUP_IPAPP, PH_BIND, TYPE_USHORT, OFUNC_SPEC };*/
const struct optdesc opt_lowport = { "lowport", NULL, OPT_LOWPORT, GROUP_IPAPP, PH_LATE, TYPE_BOOL, OFUNC_SPEC }; const struct optdesc opt_lowport = { "lowport", NULL, OPT_LOWPORT, GROUP_IPAPP, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
#if WITH_IP4 #if _WITH_IP4
/* we expect the form "host:port" */ /* we expect the form "host:port" */
int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd, int xioflags, xiofile_t *xxfd,
@ -42,8 +42,6 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
Error2("%s: wrong number of parameters (%d instead of 2)", argv[0], argc-1); Error2("%s: wrong number of parameters (%d instead of 2)", argv[0], argc-1);
} }
xfd->howtoend = END_SHUTDOWN;
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
@ -124,7 +122,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
} }
/* parent process */ /* parent process */
Notice1("forked off child process "F_pid, pid); Notice1("forked off child process "F_pid, pid);
Close(xfd->fd); Close(xfd->fd1);
/* with and without retry */ /* with and without retry */
Nanosleep(&xfd->intervall, NULL); Nanosleep(&xfd->intervall, NULL);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
@ -214,10 +212,10 @@ int
sockaddr_info((struct sockaddr *)them, *themlen, infobuff, sizeof(infobuff))); sockaddr_info((struct sockaddr *)them, *themlen, infobuff, sizeof(infobuff)));
return STAT_OK; return STAT_OK;
} }
#endif /* WITH_IP4 */ #endif /* _WITH_IP4 */
#if WITH_TCP && WITH_LISTEN #if _WITH_TCP && WITH_LISTEN
int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0,
const char *portname, int *pf, int ipproto, const char *portname, int *pf, int ipproto,
unsigned long res_opts0, unsigned long res_opts0,
@ -271,7 +269,8 @@ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts,
#endif #endif
} }
fd->stream.howtoend = END_SHUTDOWN; fd->stream.howtoshut = XIOSHUT_DOWN;
fd->stream.howtoclose = XIOCLOSE_CLOSE;
if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1; if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
@ -293,6 +292,6 @@ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts,
return result; return result;
return 0; return 0;
} }
#endif /* WITH_IP4 && WITH_TCP && WITH_LISTEN */ #endif /* _WITH_IP4 && _WITH_TCP && WITH_LISTEN */
#endif /* WITH_TCP || WITH_UDP */ #endif /* _WITH_TCP || _WITH_UDP */

View file

@ -115,46 +115,24 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
#if 1 if ((xfd->fd1 = Socket(pf, socktype, proto)) < 0) {
if (dofork) {
#if HAVE_SIGACTION
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_NOCLDSTOP|SA_RESTART
#ifdef SA_NOMASK
|SA_NOMASK
#endif
;
act.sa_handler = childdied;
if (Sigaction(SIGCHLD, &act, NULL) < 0) {
/*! man does not say that errno is defined */
Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied, strerror(errno));
}
#else /* HAVE_SIGACTION */
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
}
#endif /* !HAVE_SIGACTION */
}
#endif /* 1 */
if ((xfd->fd = Socket(pf, socktype, proto)) < 0) {
Msg4(level, Msg4(level,
"socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
xfd->fdtype = FDTYPE_SINGLE;
applyopts(xfd->fd, opts, PH_PASTSOCKET); applyopts(xfd->fd1, opts, PH_PASTSOCKET);
applyopts_cloexec(xfd->fd, opts); applyopts_cloexec(xfd->fd1, opts);
applyopts(xfd->fd, opts, PH_PREBIND); applyopts(xfd->fd1, opts, PH_PREBIND);
applyopts(xfd->fd, opts, PH_BIND); applyopts(xfd->fd1, opts, PH_BIND);
if (Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { if (Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd, Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1,
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
strerror(errno)); strerror(errno));
Close(xfd->fd); Close(xfd->fd1);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -166,12 +144,12 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
/* under some circumstances (e.g., TCP listen on port 0) bind() fills empty /* under some circumstances (e.g., TCP listen on port 0) bind() fills empty
fields that we want to know. */ fields that we want to know. */
salen = sizeof(sa); salen = sizeof(sa);
if (Getsockname(xfd->fd, us, &uslen) < 0) { if (Getsockname(xfd->fd1, us, &uslen) < 0) {
Warn4("getsockname(%d, %p, {%d}): %s", Warn4("getsockname(%d, %p, {%d}): %s",
xfd->fd, &us, uslen, strerror(errno)); xfd->fd1, &us, uslen, strerror(errno));
} }
applyopts(xfd->fd, opts, PH_PASTBIND); applyopts(xfd->fd1, opts, PH_PASTBIND);
#if WITH_UNIX #if WITH_UNIX
if (us->sa_family == AF_UNIX) { if (us->sa_family == AF_UNIX) {
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
@ -181,8 +159,8 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
#endif /* WITH_UNIX */ #endif /* WITH_UNIX */
retropt_int(opts, OPT_BACKLOG, &backlog); retropt_int(opts, OPT_BACKLOG, &backlog);
if (Listen(xfd->fd, backlog) < 0) { if (Listen(xfd->fd1, backlog) < 0) {
Error3("listen(%d, %d): %s", xfd->fd, backlog, strerror(errno)); Error3("listen(%d, %d): %s", xfd->fd1, backlog, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -229,9 +207,9 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
do { do {
/*? int level = E_ERROR;*/ /*? int level = E_ERROR;*/
Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname))); Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname)));
ps = Accept(xfd->fd, (struct sockaddr *)&sa, &salen); ps = Accept(xfd->fd1, (struct sockaddr *)&sa, &salen);
if (ps >= 0) { if (ps >= 0) {
/*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", xfd->fd, &sa, salen, ps);*/ /*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", xfd->fd1, &sa, salen, ps);*/
break; /* success, break out of loop */ break; /* success, break out of loop */
} }
if (errno == EINTR) { if (errno == EINTR) {
@ -239,12 +217,12 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
} }
if (errno == ECONNABORTED) { if (errno == ECONNABORTED) {
Notice4("accept(%d, %p, {"F_Zu"}): %s", Notice4("accept(%d, %p, {"F_Zu"}): %s",
xfd->fd, &sa, salen, strerror(errno)); xfd->fd1, &sa, salen, strerror(errno));
continue; continue;
} }
Msg4(level, "accept(%d, %p, {"F_Zu"}): %s", Msg4(level, "accept(%d, %p, {"F_Zu"}): %s",
xfd->fd, &sa, salen, strerror(errno)); xfd->fd1, &sa, salen, strerror(errno));
Close(xfd->fd); Close(xfd->fd1);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} while (true); } while (true);
applyopts_cloexec(ps, opts); applyopts_cloexec(ps, opts);
@ -271,21 +249,21 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
sockaddr_info((struct sockaddr *)pa, pas, sockaddr_info((struct sockaddr *)pa, pas,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
applyopts(xfd->fd, opts, PH_FD); applyopts(xfd->fd1, opts, PH_FD);
applyopts(xfd->fd, opts, PH_CONNECTED); applyopts(xfd->fd1, opts, PH_CONNECTED);
if (dofork) { if (dofork) {
if ((pid = Fork()) < 0) { if ((pid = Fork()) < 0) {
Msg1(level, "fork(): %s", strerror(errno)); Msg1(level, "fork(): %s", strerror(errno));
Close(xfd->fd); Close(xfd->fd1);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
if (pid == 0) { /* child */ if (pid == 0) { /* child */
if (Close(xfd->fd) < 0) { if (Close(xfd->fd1) < 0) {
Info2("close(%d): %s", xfd->fd, strerror(errno)); Info2("close(%d): %s", xfd->fd1, strerror(errno));
} }
xfd->fd = ps; xfd->fd1 = ps;
#if WITH_RETRY #if WITH_RETRY
/* !? */ /* !? */
@ -317,10 +295,10 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
Notice1("forked off child process "F_pid, pid); Notice1("forked off child process "F_pid, pid);
Info("still listening"); Info("still listening");
} else { } else {
if (Close(xfd->fd) < 0) { if (Close(xfd->fd1) < 0) {
Info2("close(%d): %s", xfd->fd, strerror(errno)); Info2("close(%d): %s", xfd->fd1, strerror(errno));
} }
xfd->fd = ps; xfd->fd1 = ps;
break; break;
} }
} }

64
xio-nop.c Normal file
View file

@ -0,0 +1,64 @@
/* $Id: xio-socks.c,v 1.25 2006/02/08 19:46:59 gerhard Exp $ */
/* Copyright Gerhard Rieger 2006-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for a degenerated address that just transfers
data */
#include "xiosysincludes.h"
#include "xioopen.h"
#include "xio-nop.h"
#if WITH_NOP
static int xioopen_nop(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd,
unsigned groups, int dummy1, int dummy2,
int dummy3);
static const struct xioaddr_inter_desc xiointer_nop0ro = { XIOADDR_PROT, "nop", 0, XIOBIT_RDONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_nop, 0, 0, 0, XIOBIT_WRONLY HELP("") };
static const struct xioaddr_inter_desc xiointer_nop0wo = { XIOADDR_PROT, "nop", 0, XIOBIT_WRONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_nop, 0, 0, 0, XIOBIT_RDONLY HELP("") };
static const struct xioaddr_inter_desc xiointer_nop0rw = { XIOADDR_PROT, "nop", 0, XIOBIT_RDWR, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_nop, 0, 0, 0, XIOBIT_RDWR HELP("") };
const union xioaddr_desc *xioaddrs_nop[] = {
(union xioaddr_desc *)&xiointer_nop0ro,
(union xioaddr_desc *)&xiointer_nop0wo,
(union xioaddr_desc *)&xiointer_nop0rw,
NULL };
static int xioopen_nop(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd,
unsigned groups, int dummy, int dummy2,
int dummy3) {
struct single *xfd = &xxfd->stream;
int result;
if (argc != 1) {
Error("address NOP takes no arguments");
return STAT_NORETRY;
}
if (xfd->fd1 < 0 && xfd->fd2 < 0) {
Error("NOP cannot be endpoint");
return STAT_NORETRY;
}
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
Notice("opening NOP");
xfd->dtype = XIODATA_STREAM;
/*xfd->fdtype = FDTYPE_DOUBLE;*/
applyopts(xfd->fd1, opts, PH_ALL);
if ((result = _xio_openlate(xfd, opts)) < 0)
return result;
return 0;
}
#endif /* WITH_NOP */

10
xio-nop.h Normal file
View file

@ -0,0 +1,10 @@
/* $Id: xio-socks.h,v 1.6 2004/06/06 19:03:28 gerhard Exp $ */
/* Copyright Gerhard Rieger 2006-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_nop_h_included
#define __xio_nop_h_included 1
extern const union xioaddr_desc *xioaddrs_nop[];
#endif /* !defined(__xio_nop_h_included) */

View file

@ -51,15 +51,44 @@ static int xioSSL_set_fd(struct single *xfd, int level);
static int xioSSL_connect(struct single *xfd, bool opt_ver, int level); static int xioSSL_connect(struct single *xfd, bool opt_ver, int level);
/* description record for ssl connect */ /* description record for inter-address ssl connect with 0 parameters */
const struct addrdesc addr_openssl = { static const struct xioaddr_inter_desc xiointer_openssl_connect0 = {
"openssl", /* keyword for selecting this address type in xioopen calls XIOADDR_INTER, /* this is an embedded address (inter module) */
"openssl-client", /* keyword for selecting this address type in xioopen calls
(canonical or main name) */ (canonical or main name) */
3, /* data flow directions this address supports on API layer: 0, /* number of required parameters */
1..read, 2..write, 3..both */ XIOBIT_ALL, /* data flow directions this address supports on API layer:
XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR */
GROUP_CHILD|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to.
You might have to specify a new group in xioopts.h */
XIOSHUT_OPENSSL,
XIOCLOSE_CLOSE,
xioopen_openssl_connect, /* a function pointer used to "open" these addresses.*/ xioopen_openssl_connect, /* a function pointer used to "open" these addresses.*/
0, /* an integer passed to xioopen_openssl; makes it possible to
use the same xioopen_openssl function for slightly different
address types. */
0, /* like previous argument */
0, /* like previous arguments, but pointer type.
No trailing comma or semicolon! */
XIOBIT_RDWR /* SSL is a bidirectional protocol */
HELP("") /* a text displayed from xio help function.
No trailing comma or semicolon!
only generates this text if WITH_HELP is != 0 */
} ;
/* description record for endpoint-address ssl connect with 2 parameters */
static const struct xioaddr_endpoint_desc xioendpoint_openssl_connect2 = {
XIOADDR_ENDPOINT, /* this is not an embedded address but a sys address */
"openssl-client", /* keyword for selecting this address type in xioopen calls
(canonical or main name) */
2, /* number of required parameters */
XIOBIT_ALL, /* data flow directions this address supports on API layer:
XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR */
GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to. GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to.
You might have to specify a new group in xioopts.h */ You might have to specify a new group in xioopts.h */
XIOSHUT_OPENSSL,
XIOCLOSE_CLOSE,
xioopen_openssl_connect, /* a function pointer used to "open" these addresses.*/
0, /* an integer passed to xioopen_openssl; makes it possible to 0, /* an integer passed to xioopen_openssl; makes it possible to
use the same xioopen_openssl function for slightly different use the same xioopen_openssl function for slightly different
address types. */ address types. */
@ -71,16 +100,53 @@ const struct addrdesc addr_openssl = {
only generates this text if WITH_HELP is != 0 */ only generates this text if WITH_HELP is != 0 */
} ; } ;
/* array containing ssl connect description records */
const union xioaddr_desc *xioaddrs_openssl_connect[] = {
(union xioaddr_desc *)&xiointer_openssl_connect0,
(union xioaddr_desc *)&xioendpoint_openssl_connect2,
NULL
};
#if WITH_LISTEN #if WITH_LISTEN
/* description record for ssl listen */ /* description record for inter-address ssl listen */
const struct addrdesc addr_openssl_listen = { static const struct xioaddr_inter_desc xiointer_openssl_listen0 = {
"openssl-listen", /* keyword for selecting this address type in xioopen calls XIOADDR_INTER, /* this is an embedded address (inter module) */
"openssl-server", /* keyword for selecting this address type in xioopen calls
(canonical or main name) */ (canonical or main name) */
3, /* data flow directions this address supports on API layer: 0, /* number of required parameters */
1..read, 2..write, 3..both */ XIOBIT_ALL, /* data flow directions this address supports on API layer:
XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR */
GROUP_CHILD|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to.
You might have to specify a new group in xioopts.h */
XIOSHUT_OPENSSL,
XIOCLOSE_CLOSE,
xioopen_openssl_listen, /* a function pointer used to "open" these addresses.*/ xioopen_openssl_listen, /* a function pointer used to "open" these addresses.*/
0, /* an integer passed to xioopen_openssl_listen; makes it possible to
use the same xioopen_openssl_listen function for slightly different
address types. */
0, /* like previous argument */
0, /* like previous arguments, but pointer type.
No trailing comma or semicolon! */
XIOBIT_RDWR /* SSL is a bidirectional protocol */
HELP("") /* a text displayed from xio help function.
No trailing comma or semicolon!
only generates this text if WITH_HELP is != 0 */
} ;
/* description record for enpoint-address ssl listen */
static const struct xioaddr_endpoint_desc xioendpoint_openssl_listen1 = {
XIOADDR_ENDPOINT, /* this is not an embedded module but a sys module */
"openssl-server", /* keyword for selecting this address type in xioopen calls
(canonical or main name) */
1, /* number of required parameters */
XIOBIT_ALL, /* data flow directions this address supports on API layer:
XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR */
GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to. GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to.
You might have to specify a new group in xioopts.h */ You might have to specify a new group in xioopts.h */
XIOSHUT_OPENSSL,
XIOCLOSE_CLOSE,
xioopen_openssl_listen, /* a function pointer used to "open" these addresses.*/
0, /* an integer passed to xioopen_openssl_listen; makes it possible to 0, /* an integer passed to xioopen_openssl_listen; makes it possible to
use the same xioopen_openssl_listen function for slightly different use the same xioopen_openssl_listen function for slightly different
address types. */ address types. */
@ -91,6 +157,13 @@ const struct addrdesc addr_openssl_listen = {
No trailing comma or semicolon! No trailing comma or semicolon!
only generates this text if WITH_HELP is != 0 */ only generates this text if WITH_HELP is != 0 */
} ; } ;
/* array containing ssl listen description records */
const union xioaddr_desc *xioaddrs_openssl_listen[] = {
(union xioaddr_desc *)&xiointer_openssl_listen0,
(union xioaddr_desc *)&xioendpoint_openssl_listen1,
NULL
};
#endif /* WITH_LISTEN */ #endif /* WITH_LISTEN */
/* both client and server */ /* both client and server */
@ -153,7 +226,7 @@ static int
{ {
struct single *xfd = &xxfd->stream; struct single *xfd = &xxfd->stream;
struct opt *opts0 = NULL; struct opt *opts0 = NULL;
const char *hostname, *portname; const char *hostname, *portname = NULL;
int pf = PF_UNSPEC; int pf = PF_UNSPEC;
int ipproto = IPPROTO_TCP; int ipproto = IPPROTO_TCP;
int socktype = SOCK_STREAM; int socktype = SOCK_STREAM;
@ -165,7 +238,7 @@ static int
bool needbind = false; bool needbind = false;
bool lowport = false; bool lowport = false;
int level; int level;
SSL_CTX* ctx; /*0 SSL_CTX* ctx;*/
bool opt_ver = true; /* verify peer certificate */ bool opt_ver = true; /* verify peer certificate */
char *opt_cert = NULL; /* file name of client certificate */ char *opt_cert = NULL; /* file name of client certificate */
int result; int result;
@ -176,15 +249,18 @@ static int
} }
xfd->flags |= XIO_DOESCONVERT; xfd->flags |= XIO_DOESCONVERT;
if (argc != 3) { xfd->howtoshut = XIOSHUT_OPENSSL;
Error1("%s: 2 parameters required", argv[0]); xfd->howtoclose = XIOCLOSE_CLOSE;
return STAT_NORETRY;
} /* we support two forms of openssl-connect */
if (argc == 3) {
hostname = argv[1]; hostname = argv[1];
portname = argv[2]; portname = argv[2];
xfd->howtoend = END_SHUTDOWN; /* a "terminal" form where we build a tcp connection to given host and
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; port */
applyopts_single(xfd, opts, PH_INIT);
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
retropt_bool(opts, OPT_FORK, &dofork); retropt_bool(opts, OPT_FORK, &dofork);
@ -192,7 +268,8 @@ static int
retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert); retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
result = result =
_xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert, &ctx); _xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert,
&xfd->para.openssl.ctx);
if (result != STAT_OK) return STAT_NORETRY; if (result != STAT_OK) return STAT_NORETRY;
result = result =
@ -202,6 +279,32 @@ static int
them, &themlen, us, &uslen, them, &themlen, us, &uslen,
&needbind, &lowport, &socktype); &needbind, &lowport, &socktype);
if (result != STAT_OK) return STAT_NORETRY; if (result != STAT_OK) return STAT_NORETRY;
} else if (argc = 1) {
/* or a "non terminal" address without required parameters */
if (xfd->fd2 < 0) {
Error("openssl-connect without hostname and port must be an embedded address");
return STAT_NORETRY;
}
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT);
retropt_bool(opts, OPT_FORK, &dofork);
retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
result =
_xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert,
&xfd->para.openssl.ctx);
if (result != STAT_OK) return STAT_NORETRY;
retropt_bool(opts, OPT_FORK, &dofork);
} else {
Error1("%s: 0 or 2 parameters required", argv[0]);
return STAT_NORETRY;
}
if (xioopts.logopt == 'm') { if (xioopts.logopt == 'm') {
Info("starting connect loop, switching to syslog"); Info("starting connect loop, switching to syslog");
@ -219,6 +322,8 @@ static int
#endif /* WITH_RETRY */ #endif /* WITH_RETRY */
level = E_ERROR; level = E_ERROR;
/*!!! this belongs only to "old" openssl-connect form */
if (portname) {
/* this cannot fork because we retrieved fork option above */ /* this cannot fork because we retrieved fork option above */
result = result =
_xioopen_connect(xfd, _xioopen_connect(xfd,
@ -243,20 +348,24 @@ static int
default: default:
return result; return result;
} }
}
/*! isn't this too early? */ /*! isn't this too early? */
if ((result = _xio_openlate(xfd, opts)) < 0) { if ((result = _xio_openlate(xfd, opts)) < 0) {
return result; return result;
} }
result = _xioopen_openssl_connect(xfd, opt_ver, ctx, level); result =
_xioopen_openssl_connect(xfd, opt_ver, xfd->para.openssl.ctx, level);
switch (result) { switch (result) {
case STAT_OK: break; case STAT_OK: break;
#if WITH_RETRY #if WITH_RETRY
case STAT_RETRYLATER: case STAT_RETRYLATER:
case STAT_RETRYNOW: case STAT_RETRYNOW:
if (xfd->forever || xfd->retry) { if (xfd->forever || xfd->retry) {
Close(xfd->fd); Close(xfd->fd1);
if (xfd->fdtype == FDTYPE_DOUBLE)
Close(xfd->fd2);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
if (result == STAT_RETRYLATER) { if (result == STAT_RETRYLATER) {
Nanosleep(&xfd->intervall, NULL); Nanosleep(&xfd->intervall, NULL);
@ -297,7 +406,9 @@ static int
} }
/* parent process */ /* parent process */
Notice1("forked off child process "F_pid, pid); Notice1("forked off child process "F_pid, pid);
Close(xfd->fd); Close(xfd->fd1);
if (xfd->fdtype == FDTYPE_DOUBLE)
Close(xfd->fd2);
sycSSL_free(xfd->para.openssl.ssl); sycSSL_free(xfd->para.openssl.ssl);
xfd->para.openssl.ssl = NULL; xfd->para.openssl.ssl = NULL;
/* with and without retry */ /* with and without retry */
@ -383,7 +494,7 @@ static int
addr_openssl */ addr_openssl */
{ {
struct single *xfd = &xxfd->stream; struct single *xfd = &xxfd->stream;
const char *portname; const char *portname = NULL;
struct opt *opts0 = NULL; struct opt *opts0 = NULL;
union sockaddr_union us_sa, *us = &us_sa; union sockaddr_union us_sa, *us = &us_sa;
socklen_t uslen = sizeof(us_sa); socklen_t uslen = sizeof(us_sa);
@ -392,7 +503,7 @@ static int
int ipproto = IPPROTO_TCP; int ipproto = IPPROTO_TCP;
/*! lowport? */ /*! lowport? */
int level; int level;
SSL_CTX* ctx; /*0 SSL_CTX* ctx;*/
bool opt_ver = true; /* verify peer certificate - changed with 1.6.0 */ bool opt_ver = true; /* verify peer certificate - changed with 1.6.0 */
char *opt_cert = NULL; /* file name of server certificate */ char *opt_cert = NULL; /* file name of server certificate */
int result; int result;
@ -403,11 +514,6 @@ static int
} }
xfd->flags |= XIO_DOESCONVERT; xfd->flags |= XIO_DOESCONVERT;
if (argc != 2) {
Error1("%s: 1 parameter required", argv[0]);
return STAT_NORETRY;
}
#if WITH_IP4 && WITH_IP6 #if WITH_IP4 && WITH_IP6
pf = xioopts.default_ip=='6'?PF_INET6:PF_INET; pf = xioopts.default_ip=='6'?PF_INET6:PF_INET;
#elif WITH_IP6 #elif WITH_IP6
@ -416,9 +522,36 @@ static int
pf = PF_INET; pf = PF_INET;
#endif #endif
portname = argv[1]; if (argc == 2) {
portname = argv[1];
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT);
retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
if (opt_cert == NULL) {
Warn("no certificate given; consider option \"cert\"");
}
result =
_xioopen_openssl_prepare(opts, xfd, true, &opt_ver, opt_cert,
&xfd->para.openssl.ctx);
if (result != STAT_OK) return STAT_NORETRY;
if (_xioopen_ipapp_listen_prepare(opts, &opts0, portname, &pf, ipproto,
xfd->para.socket.ip.res_opts[1],
xfd->para.socket.ip.res_opts[0],
us, &uslen, &socktype)
!= STAT_OK) {
return STAT_NORETRY;
}
} else if (argc == 1) {
if (xfd->fd1 < 0) {
Error("openssl-listen without port must be an embedded address");
return STAT_NORETRY;
}
xfd->howtoend = END_SHUTDOWN;
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
@ -430,18 +563,15 @@ static int
applyopts(-1, opts, PH_EARLY); applyopts(-1, opts, PH_EARLY);
result = result =
_xioopen_openssl_prepare(opts, xfd, true, &opt_ver, opt_cert, &ctx); _xioopen_openssl_prepare(opts, xfd, true, &opt_ver, opt_cert,
&xfd->para.openssl.ctx);
if (result != STAT_OK) return STAT_NORETRY; if (result != STAT_OK) return STAT_NORETRY;
if (_xioopen_ipapp_listen_prepare(opts, &opts0, portname, &pf, ipproto, } else {
xfd->para.socket.ip.res_opts[1], Error1("%s: 1 parameter required", argv[0]);
xfd->para.socket.ip.res_opts[0], return -1;
us, &uslen, &socktype)
!= STAT_OK) {
return STAT_NORETRY;
} }
xfd->addr = &addr_openssl_listen;
xfd->dtype = XIODATA_OPENSSL; xfd->dtype = XIODATA_OPENSSL;
while (true) { /* loop over failed attempts */ while (true) { /* loop over failed attempts */
@ -453,6 +583,7 @@ static int
#endif /* WITH_RETRY */ #endif /* WITH_RETRY */
level = E_ERROR; level = E_ERROR;
if (portname) {
/* tcp listen; this can fork() for us; it only returns on error or on /* tcp listen; this can fork() for us; it only returns on error or on
successful establishment of tcp connection */ successful establishment of tcp connection */
result = _xioopen_listen(xfd, xioflags, result = _xioopen_listen(xfd, xioflags,
@ -464,6 +595,7 @@ static int
E_ERROR E_ERROR
#endif /* WITH_RETRY */ #endif /* WITH_RETRY */
); );
}
/*! not sure if we should try again on retry/forever */ /*! not sure if we should try again on retry/forever */
switch (result) { switch (result) {
case STAT_OK: break; case STAT_OK: break;
@ -484,8 +616,8 @@ static int
default: default:
return result; return result;
} }
result =
result = _xioopen_openssl_listen(xfd, opt_ver, ctx, level); _xioopen_openssl_listen(xfd, opt_ver, xfd->para.openssl.ctx, level);
switch (result) { switch (result) {
case STAT_OK: break; case STAT_OK: break;
#if WITH_RETRY #if WITH_RETRY
@ -537,12 +669,11 @@ int _xioopen_openssl_listen(struct single *xfd,
} }
/* assign the network connection to the SSL object */ /* assign the network connection to the SSL object */
if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->fd) <= 0) { ret = xioSSL_set_fd(xfd, level);
if (ERR_peek_error() == 0) Msg(level, "SSL_set_fd() failed"); if (ret != STAT_OK) {
while (err = ERR_get_error()) { sycSSL_free(xfd->para.openssl.ssl);
Msg2(level, "SSL_set_fd(, %d): %s", xfd->para.openssl.ssl = NULL;
xfd->fd, ERR_error_string(err, NULL)); return ret;
}
} }
#if WITH_DEBUG #if WITH_DEBUG
@ -634,7 +765,6 @@ int
unsigned long err; unsigned long err;
int result; int result;
xfd->addr = &addr_openssl;
xfd->dtype = XIODATA_OPENSSL; xfd->dtype = XIODATA_OPENSSL;
retropt_bool(opts, OPT_OPENSSL_FIPS, &opt_fips); retropt_bool(opts, OPT_OPENSSL_FIPS, &opt_fips);
@ -751,7 +881,7 @@ int
if ((result = if ((result =
openssl_SSL_ERROR_SSL(E_ERROR, "SSL_CTX_load_verify_locations")) openssl_SSL_ERROR_SSL(E_ERROR, "SSL_CTX_load_verify_locations"))
!= STAT_OK) { != STAT_OK) {
/*! free ctx */ SSL_CTX_free(*ctx); *ctx = NULL;
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} }
@ -963,14 +1093,33 @@ static int xioSSL_set_fd(struct single *xfd, int level) {
unsigned long err; unsigned long err;
/* assign a network connection to the SSL object */ /* assign a network connection to the SSL object */
if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->fd) <= 0) { if (xfd->fd2 < 0) {
if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->fd1) <= 0) {
Msg(level, "SSL_set_fd() failed"); Msg(level, "SSL_set_fd() failed");
while (err = ERR_get_error()) { while (err = ERR_get_error()) {
Msg2(level, "SSL_set_fd(, %d): %s", Msg2(level, "SSL_set_fd(, %d): %s",
xfd->fd, ERR_error_string(err, NULL)); xfd->fd2, ERR_error_string(err, NULL));
} }
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} else {
if (sycSSL_set_rfd(xfd->para.openssl.ssl, xfd->fd1) <= 0) {
Msg(level, "SSL_set_rfd() failed");
while (err = ERR_get_error()) {
Msg2(level, "SSL_set_rfd(, %d): %s",
xfd->fd1, ERR_error_string(err, NULL));
}
return STAT_RETRYLATER;
}
if (sycSSL_set_wfd(xfd->para.openssl.ssl, xfd->fd2) <= 0) {
Msg(level, "SSL_set_wfd() failed");
while (err = ERR_get_error()) {
Msg2(level, "SSL_set_wfd(, %d): %s",
xfd->fd2, ERR_error_string(err, NULL));
}
return STAT_RETRYLATER;
}
}
return STAT_OK; return STAT_OK;
} }

View file

@ -10,8 +10,8 @@
#define SSLIO_BASE 0x53530000 /* "SSxx" */ #define SSLIO_BASE 0x53530000 /* "SSxx" */
#define SSLIO_MASK 0xffff0000 #define SSLIO_MASK 0xffff0000
extern const struct addrdesc addr_openssl; extern const union xioaddr_desc *xioaddrs_openssl_connect[];
extern const struct addrdesc addr_openssl_listen; extern const union xioaddr_desc *xioaddrs_openssl_listen[];
extern const struct optdesc opt_openssl_cipherlist; extern const struct optdesc opt_openssl_cipherlist;
extern const struct optdesc opt_openssl_method; extern const struct optdesc opt_openssl_method;

View file

@ -12,16 +12,20 @@
#if WITH_PIPE #if WITH_PIPE
static int xioopen_fifo(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); static int xioopen_fifo0(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts); static int xioopen_fifo1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
static const struct xioaddr_endpoint_desc xioaddr_pipe0 = { XIOADDR_SYS, "pipe", 0, XIOBIT_RDWR, GROUP_FD|GROUP_NAMED|GROUP_OPEN|GROUP_FIFO, XIOSHUT_CLOSE, XIOCLOSE_CLOSE, xioopen_fifo0, 0, 0, 0 HELP("") };
static const struct xioaddr_endpoint_desc xioaddr_pipe1 = { XIOADDR_SYS, "pipe", 1, XIOBIT_ALL, GROUP_FD|GROUP_NAMED|GROUP_OPEN|GROUP_FIFO, XIOSHUT_CLOSE, XIOCLOSE_CLOSE, xioopen_fifo1, 0, 0, 0 HELP(":<filename>") };
const struct addrdesc addr_pipe = { "pipe", 3, xioopen_fifo, GROUP_FD|GROUP_NAMED|GROUP_OPEN|GROUP_FIFO, 0, 0, 0 HELP(":<filename>") }; const union xioaddr_desc *xioaddrs_pipe[] = {
(union xioaddr_desc *)&xioaddr_pipe0,
(union xioaddr_desc *)&xioaddr_pipe1,
NULL };
/* process an unnamed bidirectional "pipe" or "fifo" or "echo" argument with /* process an unnamed bidirectional "pipe" or "fifo" or "echo" argument with
options */ options */
static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) { static int xioopen_fifo0(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *sock, unsigned groups, int dummy1, int dummy2, int dummy3) {
struct opt *opts2; struct opt *opts2;
int filedes[2]; int filedes[2];
int numleft; int numleft;
@ -37,11 +41,12 @@ static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) {
/*0 Info2("pipe({%d,%d})", filedes[0], filedes[1]);*/ /*0 Info2("pipe({%d,%d})", filedes[0], filedes[1]);*/
sock->common.tag = XIO_TAG_RDWR; sock->common.tag = XIO_TAG_RDWR;
sock->stream.dtype = XIODATA_PIPE; sock->stream.dtype = XIODATA_2PIPE;
sock->stream.fd = filedes[0]; sock->stream.fd1 = filedes[0];
sock->stream.para.bipipe.fdout = filedes[1]; sock->stream.fd2 = filedes[1];
applyopts_cloexec(sock->stream.fd, opts); sock->stream.fdtype = FDTYPE_DOUBLE;
applyopts_cloexec(sock->stream.para.bipipe.fdout, opts); applyopts_cloexec(sock->stream.fd1, opts);
applyopts_cloexec(sock->stream.fd2, opts);
/* one-time and input-direction options, no second application */ /* one-time and input-direction options, no second application */
retropt_bool(opts, OPT_IGNOREEOF, &sock->stream.ignoreeof); retropt_bool(opts, OPT_IGNOREEOF, &sock->stream.ignoreeof);
@ -52,7 +57,7 @@ static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) {
} }
/* apply options to first FD */ /* apply options to first FD */
if ((result = applyopts(sock->stream.fd, opts, PH_ALL)) < 0) { if ((result = applyopts(sock->stream.fd1, opts, PH_ALL)) < 0) {
return result; return result;
} }
if ((result = applyopts_single(&sock->stream, opts, PH_ALL)) < 0) { if ((result = applyopts_single(&sock->stream, opts, PH_ALL)) < 0) {
@ -60,7 +65,7 @@ static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) {
} }
/* apply options to second FD */ /* apply options to second FD */
if ((result = applyopts(sock->stream.para.bipipe.fdout, opts2, PH_ALL)) < 0) if ((result = applyopts(sock->stream.fd2, opts2, PH_ALL)) < 0)
{ {
return result; return result;
} }
@ -75,7 +80,7 @@ static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) {
/* open a named pipe/fifo */ /* open a named pipe/fifo */
static int xioopen_fifo(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) { static int xioopen_fifo1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) {
const char *pipename = argv[1]; const char *pipename = argv[1];
int rw = (xioflags & XIO_ACCMODE); int rw = (xioflags & XIO_ACCMODE);
#if HAVE_STAT64 #if HAVE_STAT64
@ -88,14 +93,6 @@ static int xioopen_fifo(int argc, const char *argv[], struct opt *opts, int xiof
mode_t mode = 0666; mode_t mode = 0666;
int result; int result;
if (argc == 1) {
return xioopen_fifo_unnamed(fd, fd->stream.opts);
}
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
}
if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1; if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
@ -166,11 +163,14 @@ static int xioopen_fifo(int argc, const char *argv[], struct opt *opts, int xiof
if ((result = _xioopen_open(pipename, rw, opts)) < 0) { if ((result = _xioopen_open(pipename, rw, opts)) < 0) {
return result; return result;
} }
fd->stream.fd = result; fd->stream.fd1 = result;
fd->stream.fdtype = FDTYPE_SINGLE;
fd->stream.howtoshut = XIOSHUTWR_NONE|XIOSHUTRD_CLOSE;
fd->stream.howtoclose = XIOCLOSE_CLOSE;
applyopts_named(pipename, opts, PH_FD); applyopts_named(pipename, opts, PH_FD);
applyopts(fd->stream.fd, opts, PH_FD); applyopts(fd->stream.fd1, opts, PH_FD);
applyopts_cloexec(fd->stream.fd, opts); applyopts_cloexec(fd->stream.fd1, opts);
return _xio_openlate(&fd->stream, opts); return _xio_openlate(&fd->stream, opts);
} }

View file

@ -1,11 +1,11 @@
/* $Id: xio-pipe.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */ /* $Id: xio-pipe.h,v 1.4.2.1 2006/07/24 19:18:02 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_pipe_h_included #ifndef __xio_pipe_h_included
#define __xio_pipe_h_included 1 #define __xio_pipe_h_included 1
const extern struct addrdesc addr_pipe; extern const union xioaddr_desc *xioaddrs_pipe[];
extern int xioopen_fifo_unnamed(char *arg, xiofile_t *sock); extern int xioopen_fifo_unnamed(char *arg, xiofile_t *sock);

View file

@ -6,6 +6,7 @@
#include "xiosysincludes.h" #include "xiosysincludes.h"
#include "xioopen.h" #include "xioopen.h"
#include "xiosigchld.h"
#include "xio-process.h" #include "xio-process.h"
#include "xio-progcall.h" #include "xio-progcall.h"
@ -41,7 +42,7 @@ const struct optdesc opt_sigquit = { "sigquit", NULL, OPT_SIGQUIT, GROUP_P
return>0: is parent process return>0: is parent process
return<0: error occurred, assume parent process and no child exists !!! return<0: error occurred, assume parent process and no child exists !!!
*/ */
int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ int _xioopen_foxec_int(int xioflags, /* XIO_RDONLY etc. */
struct single *fd, struct single *fd,
unsigned groups, unsigned groups,
struct opt **copts /* in: opts; out: opts for child */ struct opt **copts /* in: opts; out: opts for child */
@ -102,6 +103,11 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
retropt_ushort(popts, OPT_FDIN, (unsigned short *)&fdi); retropt_ushort(popts, OPT_FDIN, (unsigned short *)&fdi);
retropt_ushort(popts, OPT_FDOUT, (unsigned short *)&fdo); retropt_ushort(popts, OPT_FDOUT, (unsigned short *)&fdo);
if (rw == XIO_WRONLY) {
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_SLEEP_SIGTERM;
}
}
if (withfork) { if (withfork) {
if (!(xioflags&XIO_MAYCHILD)) { if (!(xioflags&XIO_MAYCHILD)) {
Error("cannot fork off child process here"); Error("cannot fork off child process here");
@ -125,15 +131,24 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (!withfork) { if (!withfork) {
/*0 struct single *stream1, *stream2;*/ /*0 struct single *stream1, *stream2;*/
free(*copts);
*copts = moveopts(popts, GROUP_ALL);
/* what if WE are sock1 ? */
#if 1
if (!(xioflags & XIO_MAYEXEC /* means exec+nofork */)) { if (!(xioflags & XIO_MAYEXEC /* means exec+nofork */)) {
Error("option nofork is not allowed here"); Error("nofork option is not allowed here");
/*!! free something */ /*!! free something */
return -1; return -1;
} }
fd->flags |= XIO_DOESEXEC; fd->flags |= XIO_DOESEXEC;
#else /*!! */
free(*copts); if (sock1 == NULL) {
*copts = moveopts(popts, GROUP_ALL); Fatal("nofork option must no be applied to first socat address");
}
#endif
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_CLOSE;
}
#if 0 /*!! */ #if 0 /*!! */
if (sock1->tag == XIO_TAG_DUAL) { if (sock1->tag == XIO_TAG_DUAL) {
@ -202,6 +217,13 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
# define PTMX "/dev/ptc" /* AIX 4.3.3 */ # define PTMX "/dev/ptc" /* AIX 4.3.3 */
#endif #endif
fd->dtype = XIODATA_PTY; fd->dtype = XIODATA_PTY;
if (fd->howtoshut == XIOSHUT_UNSPEC) {
fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP;
}
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM;
}
#if HAVE_DEV_PTMX || HAVE_DEV_PTC #if HAVE_DEV_PTMX || HAVE_DEV_PTC
if (usebestpty || useptmx) { if (usebestpty || useptmx) {
if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) { if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) {
@ -235,7 +257,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
Warn2("ttyname(%d): %s", ptyfd, strerror(errno)); Warn2("ttyname(%d): %s", ptyfd, strerror(errno));
} }
} }
strncpy(ptyname, tn, MAXPTYNAMELEN); strncpy(ptyname, tn, MAXPTYNAMELEN); /*! ttyname_r() */
if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) { if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) {
Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno)); Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno));
} else { } else {
@ -283,8 +305,11 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
applyopts_cloexec(ptyfd, popts);/*!*/ applyopts_cloexec(ptyfd, popts);/*!*/
if (fd->howtoend = END_UNSPEC) { if (fd->howtoshut == XIOSHUT_UNSPEC) {
fd->howtoend = END_CLOSE_KILL; fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP;
}
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM;
} }
/* this for parent, was after fork */ /* this for parent, was after fork */
@ -292,7 +317,8 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
applyopts(ptyfd, popts, PH_LATE); applyopts(ptyfd, popts, PH_LATE);
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
fd->fd = ptyfd; fd->fd1 = ptyfd;
fd->fdtype = FDTYPE_SINGLE;
/* this for child, was after fork */ /* this for child, was after fork */
applyopts(ttyfd, *copts, PH_FD); applyopts(ttyfd, *copts, PH_FD);
@ -301,13 +327,23 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (usepipes) { if (usepipes) {
struct opt *popts2, *copts2; struct opt *popts2, *copts2;
if (rw == XIO_RDWR) if (rw == XIO_RDWR) {
fd->dtype = XIODATA_2PIPE; fd->dtype = XIODATA_2PIPE;
}
if (fd->howtoshut == XIOSHUT_UNSPEC) {
fd->howtoshut = XIOSHUT_CLOSE;
}
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_CLOSE;
}
if (rw != XIO_WRONLY) { if (rw != XIO_WRONLY) {
if (Pipe(rdpip) < 0) { if (Pipe(rdpip) < 0) {
Error2("pipe(%p): %s", rdpip, strerror(errno)); Error2("pipe(%p): %s", rdpip, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} else {
rdpip[0] = rdpip[1] = -1;
} }
/*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/ /*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/
/* rdpip[0]: read by socat; rdpip[1]: write by child */ /* rdpip[0]: read by socat; rdpip[1]: write by child */
@ -331,6 +367,8 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
Error2("pipe(%p): %s", wrpip, strerror(errno)); Error2("pipe(%p): %s", wrpip, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} else {
wrpip[0] = wrpip[1] = -1;
} }
/*0 Info2("pipe({%d,%d})", wrpip[0], wrpip[1]);*/ /*0 Info2("pipe({%d,%d})", wrpip[0], wrpip[1]);*/
@ -340,20 +378,25 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
applyopts(wrpip[1], popts2, PH_FD); applyopts(wrpip[1], popts2, PH_FD);
applyopts(wrpip[0], copts2, PH_FD); applyopts(wrpip[0], copts2, PH_FD);
} }
if (fd->howtoend == END_UNSPEC) {
fd->howtoend = END_CLOSE_KILL;
}
/* this for parent, was after fork */ /* this for parent, was after fork */
switch (rw) { switch (rw) {
case XIO_RDONLY: fd->fd = rdpip[0]; break; case XIO_RDONLY:
case XIO_WRONLY: fd->fd = wrpip[1]; break; fd->fd1 = rdpip[0];
case XIO_RDWR: fd->fd = rdpip[0]; fd->fdtype = FDTYPE_SINGLE;
fd->para.exec.fdout = wrpip[1]; break;
case XIO_WRONLY:
fd->fd1 = wrpip[1];
fd->fdtype = FDTYPE_SINGLE;
break;
case XIO_RDWR:
fd->fd1 = rdpip[0];
fd->fd2 = wrpip[1];
fd->fdtype = FDTYPE_DOUBLE;
break; break;
} }
applyopts(fd->fd, popts, PH_FD); applyopts(fd->fd1, popts, PH_FD);
applyopts(fd->fd, popts, PH_LATE); applyopts(fd->fd1, popts, PH_LATE);
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
} else { } else {
d = AF_UNIX; type = SOCK_STREAM; d = AF_UNIX; type = SOCK_STREAM;
@ -385,29 +428,42 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
applyopts(sv[1], popts, PH_BIND); applyopts(sv[1], popts, PH_BIND);
applyopts(sv[1], popts, PH_PASTBIND); applyopts(sv[1], popts, PH_PASTBIND);
if (fd->howtoend == END_UNSPEC) { if (fd->howtoshut == XIOSHUT_UNSPEC) {
fd->howtoend = END_SHUTDOWN_KILL; fd->howtoshut = XIOSHUT_DOWN;
}
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_SIGTERM;
} }
/* this for parent, was after fork */ /* this for parent, was after fork */
fd->fd = sv[0]; fd->fd1 = sv[0];
applyopts(fd->fd, popts, PH_FD); fd->fdtype = FDTYPE_SINGLE;
applyopts(fd->fd, popts, PH_LATE); applyopts(fd->fd1, popts, PH_FD);
applyopts(fd->fd1, popts, PH_LATE);
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
} }
/*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL) /*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL)
return STAT_RETRYLATER;*/ return STAT_RETRYLATER;*/
retropt_bool(*copts, OPT_STDERR, &withstderr); retropt_bool(*copts, OPT_STDERR, &withstderr);
#if 0
if (Signal(SIGCHLD, childdied) == SIG_ERR) { if (Signal(SIGCHLD, childdied) == SIG_ERR) {
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno)); Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
} }
#endif
if (withfork) { if (withfork) {
const char *forkwaitstring; const char *forkwaitstring;
int forkwaitsecs = 0; int forkwaitsecs = 0;
sigset_t set, oldset;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
Sigprocmask(SIG_BLOCK, &set, &oldset); /* disable SIGCHLD */
pid = Fork(); pid = Fork();
if (pid < 0) { if (pid < 0) {
Sigprocmask(SIG_SETMASK, &oldset, NULL);
Error1("fork(): %s", strerror(errno)); Error1("fork(): %s", strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -417,11 +473,18 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
Sleep(forkwaitsecs); Sleep(forkwaitsecs);
} }
if (pid > 0) {
/* for parent (this is our socat process) */
xiosigchld_register(pid, xiosigaction_child, fd);
Sigprocmask(SIG_SETMASK, &oldset, NULL); /* disable SIGCHLD */
}
if (pid == 0) { /* child */ if (pid == 0) { /* child */
/* drop parents locks, reset FIPS... */ /* drop parents locks, reset FIPS... */
if (xio_forked_inchild() != 0) { if (xio_forked_inchild() != 0) {
Exit(1); Exit(1);
} }
Sigprocmask(SIG_SETMASK, &oldset, NULL); /* disable SIGCHLD */
} }
} }
if (!withfork || pid == 0) { /* child */ if (!withfork || pid == 0) { /* child */
@ -580,19 +643,23 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
return STAT_RETRYLATER; return STAT_RETRYLATER;
#endif #endif
if (0) {
; /* for canonical reasons */
#if HAVE_PTY #if HAVE_PTY
if (usepty) { } else if (usepty) {
if (Close(ttyfd) < 0) { if (Close(ttyfd) < 0) {
Info2("close(%d): %s", ttyfd, strerror(errno)); Info2("close(%d): %s", ttyfd, strerror(errno));
} }
} /*0 else*/
#endif /* HAVE_PTY */ #endif /* HAVE_PTY */
#if 0 #if 1
if (usepipes) { } else if (usepipes) {
} else { if (wrpip[0] >= 0) Close(wrpip[0]);
if (rdpip[1] >= 0) Close(rdpip[1]);
} else { /* socketpair() */
Close(sv[1]);
} }
#endif #endif
fd->para.exec.pid = pid; fd->child.pid = pid;
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
applyopts_signal(fd, popts); applyopts_signal(fd, popts);
@ -604,6 +671,639 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
return pid; /* indicate parent (main) process */ return pid; /* indicate parent (main) process */
} }
/* fork for exec/system, but return before exec'ing.
return=0: is child process
return>0: is parent process
return<0: error occurred, assume parent process and no child exists !!!
*/
int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
struct single *fd,
unsigned groups,
struct opt **copts /* in: opts; out: opts for child */
) {
struct opt *popts; /* parent process options */
int numleft;
int d, type, protocol, sv[2], rdpip[2], wrpip[2];
int rw = (xioflags & XIO_ACCMODE);
bool usepipes = false;
#if HAVE_PTY
int ptyfd = -1, ttyfd = -1;
bool usebestpty = false; /* use the best available way to open pty */
#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
bool useptmx = false; /* use /dev/ptmx or equivalent */
#endif
#if HAVE_OPENPTY
bool useopenpty = false; /* try only openpty */
#endif /* HAVE_OPENPTY */
bool usepty = false; /* any of the pty options is selected */
char ptyname[MAXPTYNAMELEN];
#endif /* HAVE_PTY */
pid_t pid = 0; /* mostly int */
short fdi = 0, fdo = 1;
short result;
bool withstderr = false;
bool nofork = false;
bool withfork;
popts = moveopts(*copts, GROUP_ALL);
if (applyopts_single(fd, popts, PH_INIT) < 0) return -1;
applyopts2(-1, popts, PH_INIT, PH_EARLY);
retropt_bool(popts, OPT_NOFORK, &nofork);
withfork = !nofork;
retropt_bool(popts, OPT_PIPES, &usepipes);
#if HAVE_PTY
retropt_bool(popts, OPT_PTY, &usebestpty);
#if HAVE_OPENPTY
retropt_bool(popts, OPT_OPENPTY, &useopenpty);
#endif
#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
retropt_bool(popts, OPT_PTMX, &useptmx);
#endif
usepty = (usebestpty
#if HAVE_OPENPTY
|| useopenpty
#endif
#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
|| useptmx
#endif
);
if (usepipes && usepty) {
Warn("_xioopen_foxec(): options \"pipes\" and \"pty\" must not be specified together; ignoring \"pipes\"");
usepipes = false;
}
#endif /* HAVE_PTY */
retropt_ushort(popts, OPT_FDIN, (unsigned short *)&fdi);
retropt_ushort(popts, OPT_FDOUT, (unsigned short *)&fdo);
if (rw == XIO_WRONLY) {
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_SLEEP_SIGTERM;
}
}
if (withfork) {
if (!(xioflags&XIO_MAYCHILD)) {
Error("cannot fork off child process here");
/*!! free something */
return -1;
}
fd->flags |= XIO_DOESCHILD;
#if HAVE_PTY
Notice2("forking off child, using %s for %s",
&("socket\0\0pipes\0\0\0pty\0\0\0\0\0"[(usepipes<<3)|(usepty<<4)]),
ddirection[rw]);
#else
Notice2("forking off child, using %s for %s",
&("socket\0\0pipes\0\0\0"[(usepipes<<3)]),
ddirection[rw]);
#endif /* HAVE_PTY */
}
applyopts(-1, popts, PH_PREBIGEN);
if (!withfork) {
/*0 struct single *stream1, *stream2;*/
free(*copts);
*copts = moveopts(popts, GROUP_ALL);
/* what if WE are sock1 ? */
#if 1
if (!(xioflags & XIO_MAYEXEC /* means exec+nofork */)) {
Error("nofork option is not allowed here");
/*!! free something */
return -1;
}
fd->flags |= XIO_DOESEXEC;
#else /*!! */
if (sock1 == NULL) {
Fatal("nofork option must no be applied to first socat address");
}
#endif
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_CLOSE;
}
#if 0 /*!! */
if (sock1->tag == XIO_TAG_DUAL) {
stream1 = &sock1->dual.stream[0]->stream;
stream2 = &sock1->dual.stream[1]->stream;
} else {
stream1 = &sock1->stream;
stream2 = &sock1->stream;
}
if (stream1->dtype == DATA_READLINE || stream2->dtype == DATA_READLINE ||
stream1->dtype == DATA_OPENSSL || stream2->dtype == DATA_OPENSSL
) {
Error("with option nofork, openssl and readline in address1 do not work");
}
if (stream1->lineterm != LINETERM_RAW ||
stream2->lineterm != LINETERM_RAW ||
stream1->ignoreeof || stream2->ignoreeof) {
Warn("due to option nofork, address1 options for lineterm and igoreeof do not apply");
}
#endif
/*! problem: when fdi==WRFD(sock[0]) or fdo==RDFD(sock[0]) */
if (rw != XIO_WRONLY) {
if (XIO_GETRDFD(sock[0]/*!!*/) == fdi) {
if (Fcntl_l(fdi, F_SETFD, 0) < 0) {
Warn2("fcntl(%d, F_SETFD, 0): %s", fdi, strerror(errno));
}
if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) {
Error3("dup2(%d, %d): %s",
XIO_GETRDFD(sock[0]), fdi, strerror(errno));
}
/*0 Info2("dup2(%d, %d)", XIO_GETRDFD(sock[0]), fdi);*/
} else {
if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) {
Error3("dup2(%d, %d): %s",
XIO_GETRDFD(sock[0]), fdi, strerror(errno));
}
/*0 Info2("dup2(%d, %d)", XIO_GETRDFD(sock[0]), fdi);*/
}
}
if (rw != XIO_RDONLY) {
if (XIO_GETWRFD(sock[0]) == fdo) {
if (Fcntl_l(fdo, F_SETFD, 0) < 0) {
Warn2("fcntl(%d, F_SETFD, 0): %s", fdo, strerror(errno));
}
if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) {
Error3("dup2(%d, %d): %s)",
XIO_GETWRFD(sock[0]), fdo, strerror(errno));
}
/*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/
} else {
if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) {
Error3("dup2(%d, %d): %s)",
XIO_GETWRFD(sock[0]), fdo, strerror(errno));
}
/*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/
}
}
} else
#if HAVE_PTY
if (usepty) {
#if defined(HAVE_DEV_PTMX)
# define PTMX "/dev/ptmx" /* Linux */
#elif HAVE_DEV_PTC
# define PTMX "/dev/ptc" /* AIX 4.3.3 */
#endif
fd->dtype = XIODATA_PTY;
if (fd->howtoshut == XIOSHUT_UNSPEC) {
fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP;
}
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM;
}
#if HAVE_DEV_PTMX || HAVE_DEV_PTC
if (usebestpty || useptmx) {
if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) {
Warn1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620): %s",
strerror(errno));
/*!*/
} else {
/*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", PTMX, ptyfd);*/
}
if (ptyfd >= 0 && ttyfd < 0) {
char *tn = NULL;
/* we used PTMX before forking */
extern char *ptsname(int);
#if HAVE_GRANTPT /* AIX, not Linux */
if (Grantpt(ptyfd)/*!*/ < 0) {
Warn2("grantpt(%d): %s", ptyfd, strerror(errno));
}
#endif /* HAVE_GRANTPT */
#if HAVE_UNLOCKPT
if (Unlockpt(ptyfd)/*!*/ < 0) {
Warn2("unlockpt(%d): %s", ptyfd, strerror(errno));
}
#endif /* HAVE_UNLOCKPT */
#if HAVE_PTSNAME /* AIX, not Linux */
if ((tn = Ptsname(ptyfd)) == NULL) {
Warn2("ptsname(%d): %s", ptyfd, strerror(errno));
}
#endif /* HAVE_PTSNAME */
if (tn == NULL) {
if ((tn = Ttyname(ptyfd)) == NULL) {
Warn2("ttyname(%d): %s", ptyfd, strerror(errno));
}
}
strncpy(ptyname, tn, MAXPTYNAMELEN); /*! ttyname_r() */
if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) {
Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno));
} else {
/*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/
}
#ifdef I_PUSH
/* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */
/* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */
/* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
/* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
if (Ioctl(ttyfd, I_FIND, "ldterm") == 0) {
Ioctl(ttyfd, I_PUSH, "ptem"); /* 0 */
Ioctl(ttyfd, I_PUSH, "ldterm"); /* 0 */
Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */
}
#endif
#if 0 /* the following block need not work */
if (ttyfd >= 0 && ((tn = Ttyname(ttyfd)) == NULL)) {
Warn2("ttyname(%d): %s", ttyfd, strerror(errno));
}
if (tn == NULL) {
Error("could not open pty");
return STAT_NORETRY;
}
#endif
Info1("opened pseudo terminal %s", tn);
}
}
#endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */
#if HAVE_OPENPTY
if (ptyfd < 0) {
int result;
if ((result = Openpty(&ptyfd, &ttyfd, ptyname, NULL, NULL)) < 0) {
Error4("openpty(%p, %p, %p, NULL, NULL): %s",
&ptyfd, &ttyfd, ptyname, strerror(errno));
return -1;
}
}
#endif /* HAVE_OPENPTY */
free(*copts);
if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
return STAT_RETRYLATER;
}
applyopts_cloexec(ptyfd, popts);/*!*/
if (fd->howtoshut == XIOSHUT_UNSPEC) {
fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP;
}
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM;
}
/* this for parent, was after fork */
applyopts(ptyfd, popts, PH_FD);
applyopts(ptyfd, popts, PH_LATE);
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
fd->fd1 = ptyfd;
fd->fdtype = FDTYPE_SINGLE;
/* this for child, was after fork */
applyopts(ttyfd, *copts, PH_FD);
} else
#endif /* HAVE_PTY */
if (usepipes) {
struct opt *popts2, *copts2;
if (rw == XIO_RDWR) {
fd->dtype = XIODATA_2PIPE;
}
if (fd->howtoshut == XIOSHUT_UNSPEC) {
fd->howtoshut = XIOSHUT_CLOSE;
}
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_CLOSE;
}
if (rw != XIO_WRONLY) {
if (Pipe(rdpip) < 0) {
Error2("pipe(%p): %s", rdpip, strerror(errno));
return STAT_RETRYLATER;
}
}
/*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/
/* rdpip[0]: read by socat; rdpip[1]: write by child */
free(*copts);
if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS))
== NULL) {
return STAT_RETRYLATER;
}
popts2 = copyopts(popts, GROUP_ALL);
copts2 = copyopts(*copts, GROUP_ALL);
if (rw != XIO_WRONLY) {
applyopts_cloexec(rdpip[0], popts);
applyopts(rdpip[0], popts, PH_FD);
applyopts(rdpip[1], *copts, PH_FD);
}
if (rw != XIO_RDONLY) {
if (Pipe(wrpip) < 0) {
Error2("pipe(%p): %s", wrpip, strerror(errno));
return STAT_RETRYLATER;
}
}
/*0 Info2("pipe({%d,%d})", wrpip[0], wrpip[1]);*/
/* wrpip[1]: write by socat; wrpip[0]: read by child */
if (rw != XIO_RDONLY) {
applyopts_cloexec(wrpip[1], popts2);
applyopts(wrpip[1], popts2, PH_FD);
applyopts(wrpip[0], copts2, PH_FD);
}
/* this for parent, was after fork */
switch (rw) {
case XIO_RDONLY:
fd->fd1 = rdpip[0];
fd->fdtype = FDTYPE_SINGLE;
break;
case XIO_WRONLY:
fd->fd1 = wrpip[1];
fd->fdtype = FDTYPE_SINGLE;
break;
case XIO_RDWR:
fd->fd1 = rdpip[0];
fd->fd2 = wrpip[1];
fd->fdtype = FDTYPE_DOUBLE;
break;
}
applyopts(fd->fd1, popts, PH_FD);
applyopts(fd->fd1, popts, PH_LATE);
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
} else {
d = AF_UNIX; type = SOCK_STREAM;
protocol = 0; /* PF_UNIX does not work on AIX */
retropt_int(popts, OPT_SO_TYPE, &type);
result = Socketpair(d, type, protocol, sv);
if (result < 0) {
Error5("socketpair(%d, %d, %d, %p): %s",
d, type, protocol, sv, strerror(errno));
return STAT_RETRYLATER;
}
/*0 Info5("socketpair(%d, %d, %d, {%d,%d})",
d, type, protocol, sv[0], sv[1]);*/
free(*copts);
if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
return STAT_RETRYLATER;
}
applyopts(sv[0], *copts, PH_PASTSOCKET);
applyopts(sv[1], popts, PH_PASTSOCKET);
applyopts_cloexec(sv[0], *copts);
applyopts(sv[0], *copts, PH_FD);
applyopts(sv[1], popts, PH_FD);
applyopts(sv[0], *copts, PH_PREBIND);
applyopts(sv[0], *copts, PH_BIND);
applyopts(sv[0], *copts, PH_PASTBIND);
applyopts(sv[1], popts, PH_PREBIND);
applyopts(sv[1], popts, PH_BIND);
applyopts(sv[1], popts, PH_PASTBIND);
if (fd->howtoshut == XIOSHUT_UNSPEC) {
fd->howtoshut = XIOSHUT_DOWN;
}
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_SIGTERM;
}
/* this for parent, was after fork */
fd->fd1 = sv[0];
fd->fdtype = FDTYPE_SINGLE;
applyopts(fd->fd1, popts, PH_FD);
applyopts(fd->fd1, popts, PH_LATE);
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
}
/*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL)
return STAT_RETRYLATER;*/
retropt_bool(*copts, OPT_STDERR, &withstderr);
#if 0
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
}
#endif
if (withfork) {
const char *forkwaitstring;
int forkwaitsecs = 0;
sigset_t set, oldset;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
Sigprocmask(SIG_BLOCK, &set, &oldset); /* disable SIGCHLD */
pid = Fork();
if (pid < 0) {
Sigprocmask(SIG_SETMASK, &oldset, NULL);
Error1("fork(): %s", strerror(errno));
return STAT_RETRYLATER;
}
/* gdb recommends to have env controlled sleep after fork */
if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
forkwaitsecs = atoi(forkwaitstring);
Sleep(forkwaitsecs);
}
if (pid > 0) {
/* for parent (this is our socat process) */
xiosigchld_register(pid, xiosigaction_child, fd);
Sigprocmask(SIG_SETMASK, &oldset, NULL); /* disable SIGCHLD */
}
if (pid == 0) { /* child */
/* drop parents locks, reset FIPS... */
if (xio_forked_inchild() != 0) {
Exit(1);
}
Sigprocmask(SIG_SETMASK, &oldset, NULL); /* disable SIGCHLD */
}
}
if (!withfork || pid == 0) { /* child */
uid_t user;
gid_t group;
if (withfork) {
if (Signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
Warn1("signal(SIGCHLD, SIG_IGN): %s", strerror(errno));
}
#if HAVE_PTY
if (usepty) {
if (rw != XIO_RDONLY && fdi != ttyfd) {
if (Dup2(ttyfd, fdi) < 0) {
Error3("dup2(%d, %d): %s", ttyfd, fdi, strerror(errno));
return STAT_RETRYLATER; }
/*0 Info2("dup2(%d, %d)", ttyfd, fdi);*/
}
if (rw != XIO_WRONLY && fdo != ttyfd) {
if (Dup2(ttyfd, fdo) < 0) {
Error3("dup2(%d, %d): %s", ttyfd, fdo, strerror(errno));
return STAT_RETRYLATER; }
/*0 Info2("dup2(%d, %d)", ttyfd, fdo);*/
}
if ((rw == XIO_RDONLY || fdi != ttyfd) &&
(rw == XIO_WRONLY || fdo != ttyfd)) {
applyopts_cloexec(ttyfd, *copts);
}
applyopts(ttyfd, *copts, PH_LATE);
applyopts(ttyfd, *copts, PH_LATE2);
} else
#endif /* HAVE_PTY */
if (usepipes) {
/* we might have a temporary conflict between what FDs are
currently allocated, and which are to be used. We try to find
a graceful solution via temporary descriptors */
int tmpi, tmpo;
if (fdi == rdpip[1]) { /* a conflict here */
if ((tmpi = Dup(wrpip[0])) < 0) {
Error2("dup(%d): %s", wrpip[0], strerror(errno));
return STAT_RETRYLATER;
}
/*0 Info2("dup(%d) -> %d", wrpip[0], tmpi);*/
rdpip[1] = tmpi;
}
if (fdo == wrpip[0]) { /* a conflict here */
if ((tmpo = Dup(rdpip[1])) < 0) {
Error2("dup(%d): %s", rdpip[1], strerror(errno));
return STAT_RETRYLATER;
}
/*0 Info2("dup(%d) -> %d", rdpip[1], tmpo);*/
wrpip[0] = tmpo;
}
if (rw != XIO_WRONLY && rdpip[1] != fdo) {
if (Dup2(rdpip[1], fdo) < 0) {
Error3("dup2(%d, %d): %s", rdpip[1], fdo, strerror(errno));
return STAT_RETRYLATER;
}
Close(rdpip[1]);
/*0 Info2("dup2(%d, %d)", rdpip[1], fdo);*/
/*0 applyopts_cloexec(fdo, *copts);*/
}
if (rw != XIO_RDONLY && wrpip[0] != fdi) {
if (Dup2(wrpip[0], fdi) < 0) {
Error3("dup2(%d, %d): %s", wrpip[0], fdi, strerror(errno));
return STAT_RETRYLATER;
}
Close(wrpip[0]);
/*0 Info2("dup2(%d, %d)", wrpip[0], fdi);*/
/*0 applyopts_cloexec(wrpip[0], *copts);*/ /* option is already consumed! */
/* applyopts_cloexec(fdi, *copts);*/ /* option is already consumed! */
}
applyopts(fdi, *copts, PH_LATE);
applyopts(fdo, *copts, PH_LATE);
applyopts(fdi, *copts, PH_LATE2);
applyopts(fdo, *copts, PH_LATE2);
} else { /* socketpair */
if (rw != XIO_RDONLY && fdi != sv[1]) {
if (Dup2(sv[1], fdi) < 0) {
Error3("dup2(%d, %d): %s", sv[1], fdi, strerror(errno));
return STAT_RETRYLATER; }
/*0 Info2("dup2(%d, %d)", sv[1], fdi);*/
}
if (rw != XIO_WRONLY && fdo != sv[1]) {
if (Dup2(sv[1], fdo) < 0) {
Error3("dup2(%d, %d): %s", sv[1], fdo, strerror(errno));
return STAT_RETRYLATER; }
/*0 Info2("dup2(%d, %d)", sv[1], fdo);*/
}
if (fdi != sv[1] && fdo != sv[1]) {
applyopts_cloexec(sv[1], *copts);
}
applyopts(fdi, *copts, PH_LATE);
applyopts(fdi, *copts, PH_LATE2);
}
} /* withfork */
else {
applyopts(-1, *copts, PH_LATE);
applyopts(-1, *copts, PH_LATE2);
}
/* what to do with stderr? */
if (withstderr) {
/* handle it just like ordinary process output, i.e. copy output fd */
if (!withfork) {
if (Dup2(fdo, 2) < 0) {
Error2("dup2(%d, 2): %s", fdo, strerror(errno));
}
/*0 Info1("dup2(%d, 2)", fdo);*/
} else
#if HAVE_PTY
if (usepty) {
if (Dup2(ttyfd, 2) < 0) {
Error2("dup2(%d, 2): %s", ttyfd, strerror(errno));
}
/*0 Info1("dup2(%d, 2)", ttyfd);*/
} else
#endif /* HAVE_PTY */
if (usepipes) {
if (Dup2(/*rdpip[1]*/ fdo, 2) < 0) {
Error2("dup2(%d, 2): %s", /*rdpip[1]*/ fdo, strerror(errno));
}
/*0 Info1("dup2(%d, 2)", rdpip[1]);*/
} else {
if (Dup2(sv[1], 2) < 0) {
Error2("dup2(%d, 2): %s", sv[1], strerror(errno));
}
/*0 Info1("dup2(%d, 2)", sv[1]);*/
}
}
_xioopen_setdelayeduser();
/* set group before user - maybe you are not permitted afterwards */
if (retropt_gidt(*copts, OPT_SETGID, &group) >= 0) {
Setgid(group);
}
if (retropt_uidt(*copts, OPT_SETUID, &user) >= 0) {
Setuid(user);
}
return 0; /* indicate child process */
}
/* for parent (this is our socat process) */
Notice1("forked off child process "F_pid, pid);
#if 0
if ((popts = copyopts(*copts,
GROUP_FD|GROUP_TERMIOS|GROUP_FORK|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_FIFO)) == NULL)
return STAT_RETRYLATER;
#endif
if (0) {
; /* for canonical reasons */
#if HAVE_PTY
} else if (usepty) {
if (Close(ttyfd) < 0) {
Info2("close(%d): %s", ttyfd, strerror(errno));
}
#endif /* HAVE_PTY */
#if 1
} else if (usepipes) {
Close(wrpip[0]);
Close(rdpip[1]);
} else { /* socketpair() */
Close(sv[1]);
}
#endif
fd->child.pid = pid;
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
applyopts_signal(fd, popts);
if ((numleft = leftopts(popts)) > 0) {
Error1("%d option(s) could not be used", numleft);
showleft(popts);
return STAT_NORETRY;
}
return pid; /* indicate parent (main) process */
}
#endif /* WITH_EXEC || WITH_SYSTEM */ #endif /* WITH_EXEC || WITH_SYSTEM */

View file

@ -1,5 +1,5 @@
/* $Id: xio-progcall.h,v 1.13 2006/02/08 19:37:15 gerhard Exp $ */ /* $Id: xio-progcall.h,v 1.13 2006/02/08 19:37:15 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_progcall_h_included #ifndef __xio_progcall_h_included
@ -18,7 +18,12 @@ extern const struct optdesc opt_sighup;
extern const struct optdesc opt_sigint; extern const struct optdesc opt_sigint;
extern const struct optdesc opt_sigquit; extern const struct optdesc opt_sigquit;
extern int _xioopen_foxec(int rw, /* O_RDONLY etc. */ extern int _xioopen_foxec_int(int rw, /* O_RDONLY etc. */
struct single *fd,
unsigned groups,
struct opt **opts
);
extern int _xioopen_foxec_end(int rw, /* O_RDONLY etc. */
struct single *fd, struct single *fd,
unsigned groups, unsigned groups,
struct opt **opts struct opt **opts

View file

@ -1,5 +1,5 @@
/* $Id: xio-proxy.c,v 1.28 2006/12/28 14:02:54 gerhard Exp $ */ /* $Id: xio-proxy.c,v 1.28 2006/12/28 14:02:54 gerhard Exp $ */
/* Copyright Gerhard Rieger 2002-2006 */ /* Copyright Gerhard Rieger 2002-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of HTTP proxy CONNECT /* this file contains the source for opening addresses of HTTP proxy CONNECT
@ -19,8 +19,12 @@
#define PROXYPORT "8080" #define PROXYPORT "8080"
static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, static int xioopen_proxy_connect2(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *fd, int xioflags, xiofile_t *xxfd,
unsigned groups, int dummy1, int dummy2,
int dummy3);
static int xioopen_proxy_connect3(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd,
unsigned groups, int dummy1, int dummy2, unsigned groups, int dummy1, int dummy2,
int dummy3); int dummy3);
@ -29,8 +33,15 @@ const struct optdesc opt_ignorecr = { "ignorecr", NULL, OPT_IGNORECR, GROUP_H
const struct optdesc opt_proxy_resolve = { "proxy-resolve", "resolve", OPT_PROXY_RESOLVE, GROUP_HTTP, PH_LATE, TYPE_BOOL, OFUNC_SPEC }; const struct optdesc opt_proxy_resolve = { "proxy-resolve", "resolve", OPT_PROXY_RESOLVE, GROUP_HTTP, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
const struct optdesc opt_proxy_authorization = { "proxy-authorization", "proxyauth", OPT_PROXY_AUTHORIZATION, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC }; const struct optdesc opt_proxy_authorization = { "proxy-authorization", "proxyauth", OPT_PROXY_AUTHORIZATION, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC };
const struct addrdesc addr_proxy_connect = { "proxy", 3, xioopen_proxy_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_HTTP|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<proxy-server>:<host>:<port>") }; static const struct xioaddr_inter_desc xioaddr_proxy_connect2 = { XIOADDR_INTER, "proxy", 2, XIOBIT_ALL, GROUP_HTTP|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_proxy_connect2, 0, 0, 0, XIOBIT_RDWR HELP(":<host>:<port>") };
static const struct xioaddr_endpoint_desc xioaddr_proxy_connect3 = { XIOADDR_ENDPOINT, "proxy", 3, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_HTTP|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_proxy_connect3, 0, 0, 0 HELP(":<proxy-server>:<host>:<port>") };
const union xioaddr_desc *xioaddrs_proxy_connect[] = {
(union xioaddr_desc *)&xioaddr_proxy_connect2,
(union xioaddr_desc *)&xioaddr_proxy_connect3,
NULL
};
/*0#define CONNLEN 40*/ /* "CONNECT 123.156.189.123:65432 HTTP/1.0\r\n\0" */ /*0#define CONNLEN 40*/ /* "CONNECT 123.156.189.123:65432 HTTP/1.0\r\n\0" */
#define CONNLEN 281 /* "CONNECT <255bytes>:65432 HTTP/1.0\r\n\0" */ #define CONNLEN 281 /* "CONNECT <255bytes>:65432 HTTP/1.0\r\n\0" */
@ -57,12 +68,12 @@ static ssize_t
xioproxy_recvbytes(struct single *xfd, char *buff, size_t buflen, int level) { xioproxy_recvbytes(struct single *xfd, char *buff, size_t buflen, int level) {
ssize_t result; ssize_t result;
do { do {
/* we need at least buflen bytes... */ /* we need at least 16 bytes... */
result = Read(xfd->fd, buff, buflen); result = Read(xfd->fd1, buff, buflen);
} while (result < 0 && errno == EINTR); /*! EAGAIN? */ } while (result < 0 && errno == EINTR); /*! EAGAIN? */
if (result < 0) { if (result < 0) {
Msg4(level, "read(%d, %p, "F_Zu"): %s", Msg4(level, "read(%d, %p, "F_Zu"): %s",
xfd->fd, buff, buflen, strerror(errno)); xfd->fd1, buff, buflen, strerror(errno));
return result; return result;
} }
if (result == 0) { if (result == 0) {
@ -75,46 +86,105 @@ static ssize_t
#define BUFLEN 2048 #define BUFLEN 2048
static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, static int xioopen_proxy_connect2(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd,
unsigned groups, int dummy1, int dummy2,
int dummy3) {
struct single *xfd = &xxfd->stream;
struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars;
const char *targetname, *targetport;
/* variables to be filled with address option values */
bool dofork = false;
int result;
if (xfd->fd1 < 0) {
Error("xioopen_proxy_connect(): proxyname missing");
return STAT_NORETRY;
}
targetname = argv[1];
targetport = argv[2];
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT);
retropt_bool(opts, OPT_FORK, &dofork);
if (dofork && !(xioflags & XIO_MAYFORK)) {
Error("fork option not allowed by application");
}
result = _xioopen_proxy_prepare(proxyvars, opts, targetname, targetport);
if (result != STAT_OK) return result;
Notice2("opening connection to %s:%u using proxy CONNECT",
proxyvars->targetaddr, proxyvars->targetport);
xfd->dtype = XIODATA_STREAM;
xfd->fdtype = FDTYPE_DOUBLE;
applyopts(xfd->fd1, opts, PH_ALL);
/*!*/
if ((result = _xio_openlate(xfd, opts)) < 0)
return result;
result = _xioopen_proxy_connect(xfd, proxyvars, E_ERROR);
switch (result) {
case STAT_OK: break;
default:
return result;
}
Notice2("successfully connected to %s:%u via proxy",
proxyvars->targetaddr, proxyvars->targetport);
return STAT_OK;
}
static int xioopen_proxy_connect3(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd, int xioflags, xiofile_t *xxfd,
unsigned groups, int dummy1, int dummy2, unsigned groups, int dummy1, int dummy2,
int dummy3) { int dummy3) {
/* we expect the form: host:host:port */ /* we expect the form: host:host:port */
struct single *xfd = &xxfd->stream; struct single *xfd = &xxfd->stream;
struct opt *opts0 = NULL;
struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars; struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars;
const char *proxyname;
char *proxyport = NULL;
const char *targetname, *targetport;
/* variables to be filled with address option values */ /* variables to be filled with address option values */
bool dofork = false; bool dofork = false;
int socktype = SOCK_STREAM;
struct opt *opts0 = NULL;
/* */ /* */
int pf = PF_UNSPEC; int pf = PF_UNSPEC;
union sockaddr_union us_sa, *us = &us_sa; union sockaddr_union us_sa, *us = &us_sa;
union sockaddr_union them_sa, *them = &them_sa; union sockaddr_union them_sa, *them = &them_sa;
socklen_t uslen = sizeof(us_sa); socklen_t uslen = sizeof(us_sa);
socklen_t themlen = sizeof(them_sa); socklen_t themlen = sizeof(them_sa);
const char *proxyname; char *proxyport = NULL;
const char *targetname, *targetport;
int ipproto = IPPROTO_TCP; int ipproto = IPPROTO_TCP;
bool needbind = false; bool needbind = false;
bool lowport = false; bool lowport = false;
int socktype = SOCK_STREAM;
int level; int level;
int result; int result;
if (argc != 4) { if (xfd->fd1 >= 0) {
Error1("%s: 3 parameters required", argv[0]); Error("xioopen_proxy_connect(): proxyname not allowed here");
return STAT_NORETRY; return STAT_NORETRY;
} }
proxyname = argv[1]; proxyname = argv[1];
targetname = argv[2]; targetname = argv[2];
targetport = argv[3]; targetport = argv[3];
xfd->howtoend = END_SHUTDOWN; xfd->howtoshut = XIOSHUT_DOWN;
xfd->howtoclose = XIOCLOSE_CLOSE;
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bool(opts, OPT_FORK, &dofork); retropt_bool(opts, OPT_FORK, &dofork);
if (dofork && !(xioflags & XIO_MAYFORK)) {
Error("fork option not allowed by application");
}
if (retropt_string(opts, OPT_PROXYPORT, &proxyport) < 0) { if (retropt_string(opts, OPT_PROXYPORT, &proxyport) < 0) {
if ((proxyport = strdup(PROXYPORT)) == NULL) { if ((proxyport = strdup(PROXYPORT)) == NULL) {
@ -133,7 +203,6 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
them, &themlen, us, &uslen, them, &themlen, us, &uslen,
&needbind, &lowport, &socktype); &needbind, &lowport, &socktype);
if (result != STAT_OK) return result; if (result != STAT_OK) return result;
Notice4("opening connection to %s:%u via proxy %s:%s", Notice4("opening connection to %s:%u via proxy %s:%s",
proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport); proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport);
@ -164,8 +233,9 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
default: default:
return result; return result;
} }
xfd->fdtype = FDTYPE_SINGLE;
applyopts(xfd->fd, opts, PH_ALL); applyopts(xfd->fd1, opts, PH_ALL);
/*!*/
if ((result = _xio_openlate(xfd, opts)) < 0) if ((result = _xio_openlate(xfd, opts)) < 0)
return result; return result;
@ -212,7 +282,8 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
} }
/* parent process */ /* parent process */
Notice1("forked off child process "F_pid, pid); Notice1("forked off child process "F_pid, pid);
Close(xfd->fd); Close(xfd->fd1);
Close(xfd->fd2);
Nanosleep(&xfd->intervall, NULL); Nanosleep(&xfd->intervall, NULL);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
continue; continue;
@ -224,9 +295,8 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
} while (true); /* end of complete open loop - drop out on success */ } while (true); /* end of complete open loop - drop out on success */
Notice4("successfully connected to %s:%u via proxy %s:%s", Notice2("successfully connected to %s:%u via proxy",
proxyvars->targetaddr, proxyvars->targetport, proxyvars->targetaddr, proxyvars->targetport);
proxyname, proxyport);
return 0; return 0;
} }
@ -275,6 +345,7 @@ int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts,
int _xioopen_proxy_connect(struct single *xfd, int _xioopen_proxy_connect(struct single *xfd,
struct proxyvars *proxyvars, struct proxyvars *proxyvars,
int level) { int level) {
int wfd;
size_t offset; size_t offset;
char request[CONNLEN]; char request[CONNLEN];
char buff[BUFLEN+1]; char buff[BUFLEN+1];
@ -286,6 +357,8 @@ int _xioopen_proxy_connect(struct single *xfd,
int state; int state;
ssize_t sresult; ssize_t sresult;
wfd = (xfd->fdtype == FDTYPE_SINGLE ? xfd->fd1 : xfd->fd2);
/* generate proxy request header - points to final target */ /* generate proxy request header - points to final target */
sprintf(request, "CONNECT %s:%u HTTP/1.0\r\n", sprintf(request, "CONNECT %s:%u HTTP/1.0\r\n",
proxyvars->targetaddr, proxyvars->targetport); proxyvars->targetaddr, proxyvars->targetport);
@ -295,13 +368,13 @@ int _xioopen_proxy_connect(struct single *xfd,
Info1("sending \"%s\"", textbuff); Info1("sending \"%s\"", textbuff);
/* write errors are assumed to always be hard errors, no retry */ /* write errors are assumed to always be hard errors, no retry */
do { do {
sresult = Write(xfd->fd, request, strlen(request)); sresult = Write(wfd, request, strlen(request));
} while (sresult < 0 && errno == EINTR); } while (sresult < 0 && errno == EINTR);
if (sresult < 0) { if (sresult < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s", Msg4(level, "write(%d, %p, "F_Zu"): %s",
xfd->fd, request, strlen(request), strerror(errno)); wfd, request, strlen(request), strerror(errno));
if (Close(xfd->fd) < 0) { if (Close(wfd) < 0) {
Info2("close(%d): %s", xfd->fd, strerror(errno)); Info2("close(%d): %s", xfd->fd2, strerror(errno));
} }
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -328,13 +401,13 @@ int _xioopen_proxy_connect(struct single *xfd,
Info1("sending \"%s\\r\\n\"", header); Info1("sending \"%s\\r\\n\"", header);
*next++ = '\r'; *next++ = '\n'; *next++ = '\0'; *next++ = '\r'; *next++ = '\n'; *next++ = '\0';
do { do {
sresult = Write(xfd->fd, header, strlen(header)); sresult = Write(wfd, header, strlen(header));
} while (sresult < 0 && errno == EINTR); } while (sresult < 0 && errno == EINTR);
if (sresult < 0) { if (sresult < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s", Msg4(level, "write(%d, %p, "F_Zu"): %s",
xfd->fd, header, strlen(header), strerror(errno)); xfd->fd2, header, strlen(header), strerror(errno));
if (Close(xfd->fd) < 0) { if (Close(wfd/*!*/) < 0) {
Info2("close(%d): %s", xfd->fd, strerror(errno)); Info2("close(%d): %s", xfd->fd2, strerror(errno));
} }
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -344,7 +417,7 @@ int _xioopen_proxy_connect(struct single *xfd,
Info("sending \"\\r\\n\""); Info("sending \"\\r\\n\"");
do { do {
sresult = Write(xfd->fd, "\r\n", 2); sresult = Write(wfd, "\r\n", 2);
} while (sresult < 0 && errno == EINTR); } while (sresult < 0 && errno == EINTR);
/*! */ /*! */

View file

@ -1,5 +1,5 @@
/* $Id: xio-proxy.h,v 1.6 2006/05/31 19:17:57 gerhard Exp $ */ /* $Id: xio-proxy.h,v 1.6.2.1 2006/07/24 19:18:10 gerhard Exp $ */
/* Copyright Gerhard Rieger 2002-2006 */ /* Copyright Gerhard Rieger 2002-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_proxy_h_included #ifndef __xio_proxy_h_included
@ -19,7 +19,7 @@ extern const struct optdesc opt_ignorecr;
extern const struct optdesc opt_proxy_resolve; extern const struct optdesc opt_proxy_resolve;
extern const struct optdesc opt_proxy_authorization; extern const struct optdesc opt_proxy_authorization;
extern const struct addrdesc addr_proxy_connect; extern const union xioaddr_desc *xioaddrs_proxy_connect[];
int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts,
const char *targetname, const char *targetport); const char *targetname, const char *targetport);

View file

@ -18,9 +18,18 @@
#define MAXPTYNAMELEN 64 #define MAXPTYNAMELEN 64
static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); static int xioopen_pty(const char *linkname, struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups);
static int xioopen_pty0(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
static int xioopen_pty1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
const struct addrdesc addr_pty = { "pty", 3, xioopen_pty, GROUP_NAMED|GROUP_FD|GROUP_TERMIOS|GROUP_PTY, 0, 0, 0 HELP("") }; static const struct xioaddr_endpoint_desc xioendpoint_pty0 = { XIOADDR_SYS, "pty", 0, XIOBIT_ALL, GROUP_NAMED|GROUP_FD|GROUP_TERMIOS|GROUP_PTY, XIOSHUT_NONE, XIOCLOSE_CLOSE, xioopen_pty0, 0, 0, 0 HELP("") };
static const struct xioaddr_endpoint_desc xioendpoint_pty1 = { XIOADDR_SYS, "pty", 1, XIOBIT_ALL, GROUP_NAMED|GROUP_FD|GROUP_TERMIOS|GROUP_PTY, XIOSHUT_NONE, XIOCLOSE_CLOSE, xioopen_pty1, 0, 0, 0 HELP(":<symlink>") };
const union xioaddr_desc* xioaddrs_pty[] = {
(union xioaddr_desc *)&xioendpoint_pty0,
(union xioaddr_desc *)&xioendpoint_pty1,
NULL
};
const struct optdesc opt_symbolic_link = { "symbolic-link", "link", OPT_SYMBOLIC_LINK, GROUP_PTY, PH_LATE, TYPE_FILENAME, OFUNC_SPEC, 0, 0 }; const struct optdesc opt_symbolic_link = { "symbolic-link", "link", OPT_SYMBOLIC_LINK, GROUP_PTY, PH_LATE, TYPE_FILENAME, OFUNC_SPEC, 0, 0 };
#if HAVE_POLL #if HAVE_POLL
@ -28,7 +37,17 @@ const struct optdesc opt_pty_wait_slave = { "pty-wait-slave", "wait-slave", OPT_
const struct optdesc opt_pty_intervall = { "pty-intervall", NULL, OPT_PTY_INTERVALL, GROUP_PTY, PH_EARLY, TYPE_TIMESPEC, OFUNC_SPEC, 0, 0 }; const struct optdesc opt_pty_intervall = { "pty-intervall", NULL, OPT_PTY_INTERVALL, GROUP_PTY, PH_EARLY, TYPE_TIMESPEC, OFUNC_SPEC, 0, 0 };
#endif /* HAVE_POLL */ #endif /* HAVE_POLL */
static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) { static int xioopen_pty0(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) {
char *linkname = NULL;
retropt_string(opts, OPT_SYMBOLIC_LINK, &linkname);
return xioopen_pty(linkname, opts, xioflags, xfd, groups);
}
static int xioopen_pty1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) {
return xioopen_pty(argv[1], opts, xioflags, xfd, groups);
}
static int xioopen_pty(const char *linkname, struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups) {
/* we expect the form: filename */ /* we expect the form: filename */
int ptyfd = -1, ttyfd = -1; int ptyfd = -1, ttyfd = -1;
#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC) #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
@ -39,7 +58,6 @@ static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xiofl
#endif /* HAVE_OPENPTY */ #endif /* HAVE_OPENPTY */
char ptyname[MAXPTYNAMELEN]; char ptyname[MAXPTYNAMELEN];
char *tn = NULL; char *tn = NULL;
char *linkname = NULL;
bool opt_unlink_close = true; /* remove symlink afterwards */ bool opt_unlink_close = true; /* remove symlink afterwards */
bool wait_slave = false; /* true would be better for many platforms, but bool wait_slave = false; /* true would be better for many platforms, but
some OSes cannot handle this, and for common some OSes cannot handle this, and for common
@ -47,8 +65,6 @@ static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xiofl
compatibility we choose "no" as default */ compatibility we choose "no" as default */
struct timespec pollintv = { PTY_INTERVALL }; struct timespec pollintv = { PTY_INTERVALL };
xfd->stream.howtoend = END_CLOSE;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1; if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1;
@ -142,7 +158,7 @@ static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xiofl
} }
#endif /* HAVE_OPENPTY */ #endif /* HAVE_OPENPTY */
if (!retropt_string(opts, OPT_SYMBOLIC_LINK, &linkname)) { if (linkname) {
if (Unlink(linkname) < 0 && errno != ENOENT) { if (Unlink(linkname) < 0 && errno != ENOENT) {
Error2("unlink(\"%s\"): %s", linkname, strerror(errno)); Error2("unlink(\"%s\"): %s", linkname, strerror(errno));
} }
@ -163,10 +179,11 @@ static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xiofl
applyopts_cloexec(ptyfd, opts);/*!*/ applyopts_cloexec(ptyfd, opts);/*!*/
xfd->stream.dtype = XIODATA_PTY; xfd->stream.dtype = XIODATA_PTY;
xfd->stream.fdtype = FDTYPE_SINGLE;
applyopts(ptyfd, opts, PH_FD); applyopts(ptyfd, opts, PH_FD);
xfd->stream.fd = ptyfd; xfd->stream.fd1 = ptyfd;
applyopts(ptyfd, opts, PH_LATE); applyopts(ptyfd, opts, PH_LATE);
if (applyopts_single(&xfd->stream, opts, PH_LATE) < 0) return -1; if (applyopts_single(&xfd->stream, opts, PH_LATE) < 0) return -1;

View file

@ -1,11 +1,11 @@
/* $Id: xio-pty.h,v 1.2 2004/10/24 13:49:53 gerhard Exp $ */ /* $Id: xio-pty.h,v 1.2.2.1 2006/07/24 19:18:15 gerhard Exp $ */
/* Copyright Gerhard Rieger 2002-2004 */ /* Copyright Gerhard Rieger 2002-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_pty_h_included #ifndef __xio_pty_h_included
#define __xio_pty_h_included 1 #define __xio_pty_h_included 1
extern const struct addrdesc addr_pty; extern const union xioaddr_desc* xioaddrs_pty[];
extern const struct optdesc opt_symbolic_link; extern const struct optdesc opt_symbolic_link;
#if HAVE_POLL #if HAVE_POLL

View file

@ -34,31 +34,41 @@ static
int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts, int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups, int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int socktype, int ipproto); int pf, int socktype, int ipproto);
static static
int _xioopen_rawip_sendto(const char *hostname, const char *protname, int _xioopen_rawip_sendto(const char *hostname, const char *protname,
struct opt *opts, int xioflags, struct opt *opts, int xioflags,
xiofile_t *xxfd, unsigned groups, int pf); xiofile_t *xxfd, unsigned groups, int pf);
const struct addrdesc addr_rawip_sendto = { "ip-sendto", 3, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") }; static const struct xioaddr_endpoint_desc xioaddr_rawip_sendto2 = { XIOADDR_SYS, "ip-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_sendto, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") };
const struct addrdesc addr_rawip_datagram= { "ip-datagram", 3, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") }; const union xioaddr_desc *xioaddrs_rawip_sendto[] = { (union xioaddr_desc *)&xioaddr_rawip_sendto2, NULL };
const struct addrdesc addr_rawip_recvfrom= { "ip-recvfrom", 3, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") }; static const struct xioaddr_endpoint_desc xioaddr_rawip_datagram2= { XIOADDR_SYS, "ip-datagram", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_datagram, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") };
const struct addrdesc addr_rawip_recv = { "ip-recv", 1, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") }; const union xioaddr_desc *xioaddrs_rawip_datagram[] = { (union xioaddr_desc *)&xioaddr_rawip_datagram2, NULL };
static const struct xioaddr_endpoint_desc xioaddr_rawip_recvfrom1= { XIOADDR_SYS, "ip-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recvfrom, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") };
const union xioaddr_desc *xioaddrs_rawip_recvfrom[] = { (union xioaddr_desc *)&xioaddr_rawip_recvfrom1, NULL };
static const struct xioaddr_endpoint_desc xioaddr_rawip_recv1 = { XIOADDR_SYS, "ip-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recv, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") };
const union xioaddr_desc *xioaddrs_rawip_recv[] = { (union xioaddr_desc *)&xioaddr_rawip_recv1, NULL };
#if WITH_IP4 #if WITH_IP4
const struct addrdesc addr_rawip4_sendto = { "ip4-sendto", 3, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4, PF_INET, 0, 0 HELP(":<host>:<protocol>") }; static const struct xioaddr_endpoint_desc xioaddr_rawip4_sendto2 = { XIOADDR_SYS, "ip4-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_sendto, PF_INET, 0, 0 HELP(":<host>:<protocol>") };
const struct addrdesc addr_rawip4_datagram= { "ip4-datagram", 3, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, PF_INET, 0, 0 HELP(":<host>:<protocol>") }; const union xioaddr_desc *xioaddrs_rawip4_sendto[] = { (union xioaddr_desc *)&xioaddr_rawip4_sendto2, NULL };
const struct addrdesc addr_rawip4_recvfrom= { "ip4-recvfrom", 3, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_CHILD|GROUP_RANGE, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") }; static const struct xioaddr_endpoint_desc xioaddr_rawip4_datagram2= { XIOADDR_SYS, "ip4-datagram", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_datagram, PF_INET, 0, 0 HELP(":<host>:<protocol>") };
const struct addrdesc addr_rawip4_recv = { "ip4-recv", 1, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") }; const union xioaddr_desc *xioaddrs_rawip4_datagram[] = { (union xioaddr_desc *)&xioaddr_rawip4_datagram2, NULL };
#endif static const struct xioaddr_endpoint_desc xioaddr_rawip4_recvfrom1= { XIOADDR_SYS, "ip4-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recvfrom, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") };
const union xioaddr_desc *xioaddrs_rawip4_recvfrom[] = { (union xioaddr_desc *)&xioaddr_rawip4_recvfrom1, NULL };
static const struct xioaddr_endpoint_desc xioaddr_rawip4_recv1 = { XIOADDR_SYS, "ip4-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recv, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") };
const union xioaddr_desc *xioaddrs_rawip4_recv[] = { (union xioaddr_desc *)&xioaddr_rawip4_recv1, NULL };
#endif /* IWITH_IP4 */
#if WITH_IP6 #if WITH_IP6
const struct addrdesc addr_rawip6_sendto = { "ip6-sendto", 3, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6, PF_INET6, 0, 0 HELP(":<host>:<protocol>") }; static const struct xioaddr_endpoint_desc xioaddr_rawip6_sendto2 = { XIOADDR_SYS, "ip6-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_sendto, PF_INET6, 0, 0 HELP(":<host>:<protocol>") };
const struct addrdesc addr_rawip6_datagram= { "ip6-datagram", 3, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, PF_INET6, 0, 0 HELP(":<host>:<protocol>") }; const union xioaddr_desc *xioaddrs_rawip6_sendto[] = { (union xioaddr_desc *)&xioaddr_rawip6_sendto2, NULL };
const struct addrdesc addr_rawip6_recvfrom= { "ip6-recvfrom", 3, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") }; static const struct xioaddr_endpoint_desc xioaddr_rawip6_datagram2= { XIOADDR_SYS, "ip6-datagram", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_datagram, PF_INET6, 0, 0 HELP(":<host>:<protocol>") };
const struct addrdesc addr_rawip6_recv = { "ip6-recv", 1, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") }; const union xioaddr_desc *xioaddrs_rawip6_datagram[] = { (union xioaddr_desc *)&xioaddr_rawip6_datagram2, NULL };
#endif static const struct xioaddr_endpoint_desc xioaddr_rawip6_recvfrom1= { XIOADDR_SYS, "ip6-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recvfrom, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") };
const union xioaddr_desc *xioaddrs_rawip6_recvfrom[] = { (union xioaddr_desc *)&xioaddr_rawip6_recvfrom1, NULL };
static const struct xioaddr_endpoint_desc xioaddr_rawip6_recv1 = { XIOADDR_SYS, "ip6-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recv, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") };
const union xioaddr_desc *xioaddrs_rawip6_recv[] = { (union xioaddr_desc *)&xioaddr_rawip6_recv1, NULL };
#endif /* WITH_IP6 */
/* we expect the form: host:protocol */ /* we expect the form: host:protocol */
/* struct sockaddr_in sa;*/ /* struct sockaddr_in sa;*/
@ -106,7 +116,6 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname,
/*return STAT_NORETRY;*/ /*return STAT_NORETRY;*/
} }
xfd->howtoend = END_SHUTDOWN;
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
/* ...res_opts[] */ /* ...res_opts[] */
@ -128,6 +137,7 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname,
uslen = socket_init(pf, &us); uslen = socket_init(pf, &us);
xfd->fdtype = FDTYPE_SINGLE;
xfd->dtype = XIODATA_RECVFROM_SKIPIP; xfd->dtype = XIODATA_RECVFROM_SKIPIP;
if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, feats, if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, feats,
@ -215,7 +225,8 @@ int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts,
protname); protname);
/*return STAT_NORETRY;*/ /*return STAT_NORETRY;*/
} }
xfd->stream.howtoend = END_NONE; xfd->stream.howtoshut = XIOSHUT_NONE;
xfd->stream.howtoclose = XIOCLOSE_CLOSE;
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_socket_pf(opts, &pf); retropt_socket_pf(opts, &pf);
@ -235,6 +246,7 @@ int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts,
needbind = true; needbind = true;
} }
xfd->stream.fdtype = FDTYPE_SINGLE;
xfd->stream.dtype = XIODATA_RECVFROM_SKIPIP_ONE; xfd->stream.dtype = XIODATA_RECVFROM_SKIPIP_ONE;
if ((result = if ((result =
_xioopen_dgram_recvfrom(&xfd->stream, xioflags, needbind?&us.soa:NULL, _xioopen_dgram_recvfrom(&xfd->stream, xioflags, needbind?&us.soa:NULL,
@ -293,6 +305,7 @@ int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts,
xfd->stream.para.socket.la.soa.sa_family = pf; xfd->stream.para.socket.la.soa.sa_family = pf;
} }
xfd->stream.fdtype = FDTYPE_SINGLE;
xfd->stream.dtype = XIODATA_RECV_SKIPIP; xfd->stream.dtype = XIODATA_RECV_SKIPIP;
result = _xioopen_dgram_recv(&xfd->stream, xioflags, NULL/*&us.soa*/, uslen, result = _xioopen_dgram_recv(&xfd->stream, xioflags, NULL/*&us.soa*/, uslen,
opts, pf, socktype, ipproto, E_ERROR); opts, pf, socktype, ipproto, E_ERROR);

View file

@ -5,17 +5,17 @@
#ifndef __xio_rawip_h_included #ifndef __xio_rawip_h_included
#define __xio_rawip_h_included 1 #define __xio_rawip_h_included 1
extern const struct addrdesc addr_rawip_sendto; extern const union xioaddr_desc *xioaddrs_rawip_sendto[];
extern const struct addrdesc addr_rawip_datagram; extern const union xioaddr_desc *xioaddrs_rawip_datagram[];
extern const struct addrdesc addr_rawip_recvfrom; extern const union xioaddr_desc *xioaddrs_rawip_recvfrom[];
extern const struct addrdesc addr_rawip_recv; extern const union xioaddr_desc *xioaddrs_rawip_recv[];
extern const struct addrdesc addr_rawip4_sendto; extern const union xioaddr_desc *xioaddrs_rawip4_sendto[];
extern const struct addrdesc addr_rawip4_datagram; extern const union xioaddr_desc *xioaddrs_rawip4_datagram[];
extern const struct addrdesc addr_rawip4_recvfrom; extern const union xioaddr_desc *xioaddrs_rawip4_recvfrom[];
extern const struct addrdesc addr_rawip4_recv; extern const union xioaddr_desc *xioaddrs_rawip4_recv[];
extern const struct addrdesc addr_rawip6_sendto; extern const union xioaddr_desc *xioaddrs_rawip6_sendto[];
extern const struct addrdesc addr_rawip6_datagram; extern const union xioaddr_desc *xioaddrs_rawip6_datagram[];
extern const struct addrdesc addr_rawip6_recvfrom; extern const union xioaddr_desc *xioaddrs_rawip6_recvfrom[];
extern const struct addrdesc addr_rawip6_recv; extern const union xioaddr_desc *xioaddrs_rawip6_recv[];
#endif /* !defined(__xio_rawip_h_included) */ #endif /* !defined(__xio_rawip_h_included) */

View file

@ -30,8 +30,13 @@ static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
int dummy1, int dummy2, int dummy3); int dummy1, int dummy2, int dummy3);
const struct addrdesc addr_readline = { static const struct xioaddr_endpoint_desc xioendpoint_readline0 = {
"readline", 3, xioopen_readline, GROUP_FD|GROUP_TERMIOS|GROUP_READLINE, 0, 0, 0 HELP(NULL) }; XIOADDR_SYS, "readline", 0, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_TERMIOS|GROUP_READLINE, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_readline, 0, 0, 0 HELP(NULL) };
const union xioaddr_desc *xioaddrs_readline[] = {
(union xioaddr_desc *)&xioendpoint_readline0,
NULL
};
const struct optdesc opt_history_file = { "history-file", "history", OPT_HISTORY_FILE, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.readline.history_file }; const struct optdesc opt_history_file = { "history-file", "history", OPT_HISTORY_FILE, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.readline.history_file };
const struct optdesc opt_prompt = { "prompt", NULL, OPT_PROMPT, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.readline.prompt }; const struct optdesc opt_prompt = { "prompt", NULL, OPT_PROMPT, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.readline.prompt };
@ -69,15 +74,16 @@ static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
} }
Notice(msgbuf); Notice(msgbuf);
xfd->stream.fd = 0; /* stdin */ xfd->stream.fd1 = 0; /* stdin */
xfd->stream.howtoend = END_NONE; xfd->stream.howtoclose = XIOCLOSE_READLINE;
xfd->stream.dtype = XIODATA_READLINE; xfd->stream.dtype = XIODATA_READLINE;
xfd->stream.fdtype = FDTYPE_SINGLE;
#if WITH_TERMIOS #if WITH_TERMIOS
if (Isatty(xfd->stream.fd)) { if (Isatty(xfd->stream.fd1)) {
if (Tcgetattr(xfd->stream.fd, &xfd->stream.savetty) < 0) { if (Tcgetattr(xfd->stream.fd1, &xfd->stream.savetty) < 0) {
Warn2("cannot query current terminal settings on fd %d. %s", Warn2("cannot query current terminal settings on fd %d. %s",
xfd->stream.fd, strerror(errno)); xfd->stream.fd1, strerror(errno));
} else { } else {
xfd->stream.ttyvalid = true; xfd->stream.ttyvalid = true;
} }
@ -87,7 +93,7 @@ static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1; if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
applyopts2(xfd->stream.fd, opts, PH_INIT, PH_FD); applyopts2(xfd->stream.fd1, opts, PH_INIT, PH_FD);
Using_history(); Using_history();
applyopts_offset(&xfd->stream, opts); applyopts_offset(&xfd->stream, opts);
@ -120,8 +126,8 @@ static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
if (xfd->stream.para.readline.history_file) { if (xfd->stream.para.readline.history_file) {
Read_history(xfd->stream.para.readline.history_file); Read_history(xfd->stream.para.readline.history_file);
} }
xiotermios_clrflag(xfd->stream.fd, 3, ICANON); xiotermios_clrflag(xfd->stream.fd1, 3, ICANON);
xiotermios_clrflag(xfd->stream.fd, 3, ECHO); xiotermios_clrflag(xfd->stream.fd1, 3, ECHO);
return _xio_openlate(&xfd->stream, opts); return _xio_openlate(&xfd->stream, opts);
} }
@ -141,40 +147,40 @@ ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) {
readline */ readline */
struct termios saveterm, setterm; struct termios saveterm, setterm;
*pipe->para.readline.dynend = '\0'; *pipe->para.readline.dynend = '\0';
Tcgetattr(pipe->fd, &saveterm); /*! error */ Tcgetattr(pipe->fd1, &saveterm); /*! error */
setterm = saveterm; setterm = saveterm;
setterm.c_lflag |= ICANON; setterm.c_lflag |= ICANON;
Tcsetattr(pipe->fd, TCSANOW, &setterm); /*!*/ Tcsetattr(pipe->fd1, TCSANOW, &setterm); /*!*/
do { do {
bytes = Read(pipe->fd, buff, bufsiz); bytes = Read(pipe->fd1, buff, bufsiz);
} while (bytes < 0 && errno == EINTR); } while (bytes < 0 && errno == EINTR);
if (bytes < 0) { if (bytes < 0) {
_errno = errno; _errno = errno;
Error4("read(%d, %p, "F_Zu"): %s", Error4("read(%d, %p, "F_Zu"): %s",
pipe->fd, buff, bufsiz, strerror(_errno)); pipe->fd1, buff, bufsiz, strerror(_errno));
errno = _errno; errno = _errno;
return -1; return -1;
} }
setterm.c_lflag &= ~ICANON; setterm.c_lflag &= ~ICANON;
Tcgetattr(pipe->fd, &setterm); /*! error */ Tcgetattr(pipe->fd1, &setterm); /*! error */
Tcsetattr(pipe->fd, TCSANOW, &saveterm); /*!*/ Tcsetattr(pipe->fd1, TCSANOW, &saveterm); /*!*/
pipe->para.readline.dynend = pipe->para.readline.dynprompt; pipe->para.readline.dynend = pipe->para.readline.dynprompt;
/*Write(pipe->fd, "\n", 1);*/ /*!*/ /*Write(pipe->fd1, "\n", 1);*/ /*!*/
return bytes; return bytes;
} }
#endif /* HAVE_REGEX_H */ #endif /* HAVE_REGEX_H */
xiotermios_setflag(pipe->fd, 3, ECHO); xiotermios_setflag(pipe->fd1, 3, ECHO);
if (pipe->para.readline.prompt || pipe->para.readline.dynprompt) { if (pipe->para.readline.prompt || pipe->para.readline.dynprompt) {
/* we must carriage return, because readline will first print the /* we must carriage return, because readline will first print the
prompt */ prompt */
ssize_t writt; ssize_t writt;
do { do {
writt = Write(pipe->fd, "\r", 1); writt = Write(pipe->fd1, "\r", 1);
} while (writt < 0 && errno == EINTR); } while (writt < 0 && errno == EINTR);
if (writt < 0) { if (writt < 0) {
Warn2("write(%d, \"\\r\", 1): %s", Warn2("write(%d, \"\\r\", 1): %s",
pipe->fd, strerror(errno)); pipe->fd1, strerror(errno));
} else if (writt < 1) { } else if (writt < 1) {
Warn1("write() only wrote "F_Zu" of 1 byte", writt); Warn1("write() only wrote "F_Zu" of 1 byte", writt);
} }
@ -191,7 +197,7 @@ ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) {
if (line == NULL) { if (line == NULL) {
return 0; /* EOF */ return 0; /* EOF */
} }
xiotermios_clrflag(pipe->fd, 3, ECHO); xiotermios_clrflag(pipe->fd1, 3, ECHO);
Add_history(line); Add_history(line);
bytes = strlen(line); bytes = strlen(line);
strncpy(buff, line, bufsiz); strncpy(buff, line, bufsiz);

View file

@ -1,11 +1,11 @@
/* $Id: xio-readline.h,v 1.4 2003/12/23 21:38:59 gerhard Exp $ */ /* $Id: xio-readline.h,v 1.4.2.1 2006/07/24 19:18:24 gerhard Exp $ */
/* Copyright Gerhard Rieger 2002, 2003 */ /* Copyright Gerhard Rieger 2002-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_readline_h_included #ifndef __xio_readline_h_included
#define __xio_readline_h_included 1 #define __xio_readline_h_included 1
extern const struct addrdesc addr_readline; extern const union xioaddr_desc *xioaddrs_readline[];
extern const struct optdesc opt_history_file; extern const struct optdesc opt_history_file;
extern const struct optdesc opt_prompt; extern const struct optdesc opt_prompt;

View file

@ -9,6 +9,7 @@
#if _WITH_SOCKET #if _WITH_SOCKET
#include "xioopen.h" #include "xioopen.h"
#include "xiosigchld.h"
#include "xio-socket.h" #include "xio-socket.h"
#include "xio-named.h" #include "xio-named.h"
#if WITH_IP4 #if WITH_IP4
@ -144,20 +145,21 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
int _errno; int _errno;
int result; int result;
if ((xfd->fd = Socket(pf, stype, proto)) < 0) { if ((xfd->fd1 = Socket(pf, stype, proto)) < 0) {
Msg4(level, Msg4(level,
"socket(%d, %d, %d): %s", pf, stype, proto, strerror(errno)); "socket(%d, %d, %d): %s", pf, stype, proto, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
xfd->fdtype = FDTYPE_SINGLE;
applyopts_offset(xfd, opts); applyopts_offset(xfd, opts);
applyopts(xfd->fd, opts, PH_PASTSOCKET); applyopts(xfd->fd1, opts, PH_PASTSOCKET);
applyopts(xfd->fd, opts, PH_FD); applyopts(xfd->fd1, opts, PH_FD);
applyopts_cloexec(xfd->fd, opts); applyopts_cloexec(xfd->fd1, opts);
applyopts(xfd->fd, opts, PH_PREBIND); applyopts(xfd->fd1, opts, PH_PREBIND);
applyopts(xfd->fd, opts, PH_BIND); applyopts(xfd->fd1, opts, PH_BIND);
#if WITH_TCP || WITH_UDP #if WITH_TCP || WITH_UDP
if (alt) { if (alt) {
union sockaddr_union sin, *sinp; union sockaddr_union sin, *sinp;
@ -214,13 +216,13 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
problem = false; problem = false;
do { /* loop over lowport bind() attempts */ do { /* loop over lowport bind() attempts */
*port = htons(i); *port = htons(i);
if (Bind(xfd->fd, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) { if (Bind(xfd->fd1, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) {
Msg4(errno==EADDRINUSE?E_INFO:level, Msg4(errno==EADDRINUSE?E_INFO:level,
"bind(%d, {%s}, "F_Zd"): %s", xfd->fd, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1,
sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)), sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
sizeof(*sinp), strerror(errno)); sizeof(*sinp), strerror(errno));
if (errno != EADDRINUSE) { if (errno != EADDRINUSE) {
Close(xfd->fd); Close(xfd->fd1);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} else { } else {
@ -230,7 +232,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
if (i == N) { if (i == N) {
Msg(level, "no low port available"); Msg(level, "no low port available");
/*errno = EADDRINUSE; still assigned */ /*errno = EADDRINUSE; still assigned */
Close(xfd->fd); Close(xfd->fd1);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} while (i != N); } while (i != N);
@ -238,31 +240,31 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
#endif /* WITH_TCP || WITH_UDP */ #endif /* WITH_TCP || WITH_UDP */
if (us) { if (us) {
if (Bind(xfd->fd, us, uslen) < 0) { if (Bind(xfd->fd1, us, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
xfd->fd, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), xfd->fd1, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)),
uslen, strerror(errno)); uslen, strerror(errno));
Close(xfd->fd); Close(xfd->fd1);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} }
applyopts(xfd->fd, opts, PH_PASTBIND); applyopts(xfd->fd1, opts, PH_PASTBIND);
applyopts(xfd->fd, opts, PH_CONNECT); applyopts(xfd->fd1, opts, PH_CONNECT);
if (xfd->para.socket.connect_timeout.tv_sec != 0 || if (xfd->para.socket.connect_timeout.tv_sec != 0 ||
xfd->para.socket.connect_timeout.tv_usec != 0) { xfd->para.socket.connect_timeout.tv_usec != 0) {
fcntl_flags = Fcntl(xfd->fd, F_GETFL); fcntl_flags = Fcntl(xfd->fd1, F_GETFL);
Fcntl_l(xfd->fd, F_SETFL, fcntl_flags|O_NONBLOCK); Fcntl_l(xfd->fd1, F_SETFL, fcntl_flags|O_NONBLOCK);
} }
result = Connect(xfd->fd, (struct sockaddr *)them, themlen); result = Connect(xfd->fd1, (struct sockaddr *)them, themlen);
_errno = errno; _errno = errno;
la.soa.sa_family = them->sa_family; lalen = sizeof(la); la.soa.sa_family = them->sa_family; lalen = sizeof(la);
if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) { if (Getsockname(xfd->fd1, &la.soa, &lalen) < 0) {
Msg4(level-1, "getsockname(%d, %p, {%d}): %s", Msg4(level-1, "getsockname(%d, %p, {%d}): %s",
xfd->fd, &la.soa, lalen, strerror(errno)); xfd->fd1, &la.soa, lalen, strerror(errno));
} }
errno = _errno; errno = _errno;
if (result < 0) { if (result < 0) {
@ -273,15 +275,15 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
fd_set readfds, writefds, exceptfds; fd_set readfds, writefds, exceptfds;
int result; int result;
Info4("connect(%d, %s, "F_Zd"): %s", Info4("connect(%d, %s, "F_Zd"): %s",
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
timeout = xfd->para.socket.connect_timeout; timeout = xfd->para.socket.connect_timeout;
FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
FD_SET(xfd->fd, &readfds); FD_SET(xfd->fd, &writefds); FD_SET(xfd->fd1, &readfds); FD_SET(xfd->fd1, &writefds);
result = result =
Select(xfd->fd+1, &readfds, &writefds, &exceptfds, &timeout); Select(xfd->fd1+1, &readfds, &writefds, &exceptfds, &timeout);
if (result < 0) { if (result < 0) {
Msg2(level, "select(%d,,,,): %s", xfd->fd+1, strerror(errno)); Msg2(level, "select(%d,,,,): %s", xfd->fd1+1, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
if (result == 0) { if (result == 0) {
@ -290,26 +292,26 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
strerror(ETIMEDOUT)); strerror(ETIMEDOUT));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
if (FD_ISSET(xfd->fd, &readfds)) { if (FD_ISSET(xfd->fd1, &readfds)) {
#if 0 #if 0
unsigned char dummy[1]; unsigned char dummy[1];
Read(xfd->fd, &dummy, 1); /* get error message */ Read(xfd->fd1, &dummy, 1); /* get error message */
Msg2(level, "connecting to %s: %s", Msg2(level, "connecting to %s: %s",
sockaddr_info(them, infobuff, sizeof(infobuff)), sockaddr_info(them, infobuff, sizeof(infobuff)),
strerror(errno)); strerror(errno));
#else #else
Connect(xfd->fd, them, themlen); /* get error message */ Connect(xfd->fd1, them, themlen); /* get error message */
Msg4(level, "connect(%d, %s, "F_Zd"): %s", Msg4(level, "connect(%d, %s, "F_Zd"): %s",
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
#endif #endif
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
/* otherwise OK */ /* otherwise OK */
Fcntl_l(xfd->fd, F_SETFL, fcntl_flags); Fcntl_l(xfd->fd1, F_SETFL, fcntl_flags);
} else { } else {
Warn4("connect(%d, %s, "F_Zd"): %s", Warn4("connect(%d, %s, "F_Zd"): %s",
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
} }
} else if (pf == PF_UNIX && errno == EPROTOTYPE) { } else if (pf == PF_UNIX && errno == EPROTOTYPE) {
@ -317,7 +319,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
the only way to distinguish stream and datagram sockets */ the only way to distinguish stream and datagram sockets */
int _errno = errno; int _errno = errno;
Info4("connect(%d, %s, "F_Zd"): %s", Info4("connect(%d, %s, "F_Zd"): %s",
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
#if 0 #if 0
Info("assuming datagram socket"); Info("assuming datagram socket");
@ -326,22 +328,21 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
memcpy(&xfd->peersa.soa, them, xfd->salen); memcpy(&xfd->peersa.soa, them, xfd->salen);
#endif #endif
/*!!! and remove bind socket */ /*!!! and remove bind socket */
Close(xfd->fd); xfd->fd = -1; Close(xfd->fd1); xfd->fd1 = -1;
errno = _errno; errno = _errno;
return -1; return -1;
} else { } else {
Msg4(level, "connect(%d, %s, "F_Zd"): %s", Msg4(level, "connect(%d, %s, "F_Zd"): %s",
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
Close(xfd->fd); Close(xfd->fd1);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} }
applyopts_fchown(xfd->fd, opts); applyopts_fchown(xfd->fd1, opts);
applyopts(xfd->fd, opts, PH_CONNECTED); applyopts(xfd->fd1, opts, PH_CONNECTED);
applyopts(xfd->fd, opts, PH_LATE); applyopts(xfd->fd1, opts, PH_LATE);
Notice1("successfully connected from local address %s", Notice1("successfully connected from local address %s",
sockaddr_info(&la.soa, themlen, infobuff, sizeof(infobuff))); sockaddr_info(&la.soa, themlen, infobuff, sizeof(infobuff)));
@ -428,7 +429,7 @@ int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
} }
/* parent process */ /* parent process */
Notice1("forked off child process "F_pid, pid); Notice1("forked off child process "F_pid, pid);
Close(xfd->fd); Close(xfd->fd1);
/* with and without retry */ /* with and without retry */
Nanosleep(&xfd->intervall, NULL); Nanosleep(&xfd->intervall, NULL);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
@ -458,7 +459,7 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
union sockaddr_union la; socklen_t lalen = sizeof(la); union sockaddr_union la; socklen_t lalen = sizeof(la);
char infobuff[256]; char infobuff[256];
if ((xfd->fd = Socket(pf, socktype, ipproto)) < 0) { if ((xfd->fd1 = Socket(pf, socktype, ipproto)) < 0) {
Msg4(level, Msg4(level,
"socket(%d, %d, %d): %s", pf, socktype, ipproto, strerror(errno)); "socket(%d, %d, %d): %s", pf, socktype, ipproto, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
@ -466,36 +467,36 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
applyopts_offset(xfd, opts); applyopts_offset(xfd, opts);
applyopts_single(xfd, opts, PH_PASTSOCKET); applyopts_single(xfd, opts, PH_PASTSOCKET);
applyopts(xfd->fd, opts, PH_PASTSOCKET); applyopts(xfd->fd1, opts, PH_PASTSOCKET);
applyopts(xfd->fd, opts, PH_FD); applyopts(xfd->fd1, opts, PH_FD);
applyopts_cloexec(xfd->fd, opts); applyopts_cloexec(xfd->fd1, opts);
applyopts(xfd->fd, opts, PH_PREBIND); applyopts(xfd->fd1, opts, PH_PREBIND);
applyopts(xfd->fd, opts, PH_BIND); applyopts(xfd->fd1, opts, PH_BIND);
if (us) { if (us) {
if (Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { if (Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
xfd->fd, sockaddr_info((struct sockaddr *)us, uslen, infobuff, sizeof(infobuff)), xfd->fd1, sockaddr_info((struct sockaddr *)us, uslen, infobuff, sizeof(infobuff)),
uslen, strerror(errno)); uslen, strerror(errno));
Close(xfd->fd); Close(xfd->fd1);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} }
applyopts(xfd->fd, opts, PH_PASTBIND); applyopts(xfd->fd1, opts, PH_PASTBIND);
/*applyopts(xfd->fd, opts, PH_CONNECT);*/ /*applyopts(xfd->fd1, opts, PH_CONNECT);*/
if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) { if (Getsockname(xfd->fd1, &la.soa, &lalen) < 0) {
Warn4("getsockname(%d, %p, {%d}): %s", Warn4("getsockname(%d, %p, {%d}): %s",
xfd->fd, &la.soa, lalen, strerror(errno)); xfd->fd1, &la.soa, lalen, strerror(errno));
} }
applyopts_fchown(xfd->fd, opts); applyopts_fchown(xfd->fd1, opts);
applyopts(xfd->fd, opts, PH_CONNECTED); applyopts(xfd->fd1, opts, PH_CONNECTED);
applyopts(xfd->fd, opts, PH_LATE); applyopts(xfd->fd1, opts, PH_LATE);
/* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */ /* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */
Notice1("successfully prepared local socket %s", Notice1("successfully prepared local socket %s",
@ -577,24 +578,24 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
} }
#endif /* 1 */ #endif /* 1 */
if ((xfd->fd = Socket(pf, socktype, proto)) < 0) { if ((xfd->fd1 = Socket(pf, socktype, proto)) < 0) {
Msg4(level, Msg4(level,
"socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
applyopts_single(xfd, opts, PH_PASTSOCKET); applyopts_single(xfd, opts, PH_PASTSOCKET);
applyopts(xfd->fd, opts, PH_PASTSOCKET); applyopts(xfd->fd1, opts, PH_PASTSOCKET);
applyopts_cloexec(xfd->fd, opts); applyopts_cloexec(xfd->fd1, opts);
applyopts(xfd->fd, opts, PH_PREBIND); applyopts(xfd->fd1, opts, PH_PREBIND);
applyopts(xfd->fd, opts, PH_BIND); applyopts(xfd->fd1, opts, PH_BIND);
if ((us != NULL) && Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { if ((us != NULL) && Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd, Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1,
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
strerror(errno)); strerror(errno));
Close(xfd->fd); Close(xfd->fd1);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -604,7 +605,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
} }
#endif #endif
applyopts(xfd->fd, opts, PH_PASTBIND); applyopts(xfd->fd1, opts, PH_PASTBIND);
#if WITH_UNIX #if WITH_UNIX
if (pf == AF_UNIX && us != NULL) { if (pf == AF_UNIX && us != NULL) {
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
@ -688,7 +689,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
if (drop) { if (drop) {
char *dummy[2]; char *dummy[2];
Recv(xfd->fd, dummy, sizeof(dummy), 0); Recv(xfd->fd1, dummy, sizeof(dummy), 0);
drop = true; drop = true;
} }
@ -702,8 +703,8 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
Notice1("receiving IP protocol %u", proto); Notice1("receiving IP protocol %u", proto);
} }
FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt); FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt);
FD_SET(xfd->fd, &in); FD_SET(xfd->fd1, &in);
if (Select(xfd->fd+1, &in, &out, &expt, NULL) > 0) { if (Select(xfd->fd1+1, &in, &out, &expt, NULL) > 0) {
break; break;
} }
@ -711,12 +712,12 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
continue; continue;
} }
Msg2(level, "select(, {%d}): %s", xfd->fd, strerror(errno)); Msg2(level, "select(, {%d}): %s", xfd->fd1, strerror(errno));
Close(xfd->fd); Close(xfd->fd1);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} while (true); } while (true);
if (xiogetpacketsrc(xfd->fd, pa, &palen) < 0) { if (xiogetpacketsrc(xfd->fd1, pa, &palen) < 0) {
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -727,16 +728,16 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
if (xiocheckpeer(xfd, pa, la) < 0) { if (xiocheckpeer(xfd, pa, la) < 0) {
/* drop packet */ /* drop packet */
char buff[512]; char buff[512];
Recv(xfd->fd, buff, sizeof(buff), 0); Recv(xfd->fd1, buff, sizeof(buff), 0);
continue; continue;
} }
Info1("permitting packet from %s", Info1("permitting packet from %s",
sockaddr_info((struct sockaddr *)pa, palen, sockaddr_info((struct sockaddr *)pa, palen,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
applyopts(xfd->fd, opts, PH_FD); applyopts(xfd->fd1, opts, PH_FD);
applyopts(xfd->fd, opts, PH_CONNECTED); applyopts(xfd->fd1, opts, PH_CONNECTED);
xfd->peersa = *(union sockaddr_union *)pa; xfd->peersa = *(union sockaddr_union *)pa;
xfd->salen = palen; xfd->salen = palen;
@ -758,7 +759,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
if ((pid = Fork()) < 0) { if ((pid = Fork()) < 0) {
Msg1(level, "fork(): %s", strerror(errno)); Msg1(level, "fork(): %s", strerror(errno));
Close(xfd->fd); Close(xfd->fd1);
Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL); Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -830,24 +831,24 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY; if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
if ((xfd->fd = Socket(pf, socktype, proto)) < 0) { if ((xfd->fd1 = Socket(pf, socktype, proto)) < 0) {
Msg4(level, Msg4(level,
"socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
applyopts_single(xfd, opts, PH_PASTSOCKET); applyopts_single(xfd, opts, PH_PASTSOCKET);
applyopts(xfd->fd, opts, PH_PASTSOCKET); applyopts(xfd->fd1, opts, PH_PASTSOCKET);
applyopts_cloexec(xfd->fd, opts); applyopts_cloexec(xfd->fd1, opts);
applyopts(xfd->fd, opts, PH_PREBIND); applyopts(xfd->fd1, opts, PH_PREBIND);
applyopts(xfd->fd, opts, PH_BIND); applyopts(xfd->fd1, opts, PH_BIND);
if ((us != NULL) && Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { if ((us != NULL) && Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd, Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1,
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
strerror(errno)); strerror(errno));
Close(xfd->fd); Close(xfd->fd1);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -857,7 +858,7 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
} }
#endif #endif
applyopts(xfd->fd, opts, PH_PASTBIND); applyopts(xfd->fd1, opts, PH_PASTBIND);
#if WITH_UNIX #if WITH_UNIX
if (pf == AF_UNIX && us != NULL) { if (pf == AF_UNIX && us != NULL) {
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/

View file

@ -1,5 +1,5 @@
/* $Id: xio-socket.h,v 1.16 2006/12/30 23:04:21 gerhard Exp $ */ /* $Id: xio-socket.h,v 1.16 2006/12/30 23:04:21 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_socket_h_included #ifndef __xio_socket_h_included

View file

@ -1,5 +1,5 @@
/* $Id: xio-socks.c,v 1.33 2006/12/28 14:06:37 gerhard Exp $ */ /* $Id: xio-socks.c,v 1.33 2006/12/28 14:06:37 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of socks4 type */ /* this file contains the source for opening addresses of socks4 type */
@ -35,10 +35,25 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
const struct optdesc opt_socksport = { "socksport", NULL, OPT_SOCKSPORT, GROUP_IP_SOCKS4, PH_LATE, TYPE_STRING, OFUNC_SPEC }; const struct optdesc opt_socksport = { "socksport", NULL, OPT_SOCKSPORT, GROUP_IP_SOCKS4, PH_LATE, TYPE_STRING, OFUNC_SPEC };
const struct optdesc opt_socksuser = { "socksuser", NULL, OPT_SOCKSUSER, GROUP_IP_SOCKS4, PH_LATE, TYPE_NAME, OFUNC_SPEC }; const struct optdesc opt_socksuser = { "socksuser", NULL, OPT_SOCKSUSER, GROUP_IP_SOCKS4, PH_LATE, TYPE_NAME, OFUNC_SPEC };
const struct addrdesc addr_socks4_connect = { "socks4", 3, xioopen_socks4_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<socks-server>:<host>:<port>") }; static const struct xioaddr_inter_desc xiointer_socks4_connect2 = { XIOADDR_INTER, "socks4", 2, XIOBIT_ALL, GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socks4_connect, 0, 0, 0, XIOBIT_RDWR HELP(":<host>:<port>") };
static const struct xioaddr_endpoint_desc xioendpoint_socks4_connect3 = { XIOADDR_ENDPOINT, "socks4", 3, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socks4_connect, 0, 0, 0 HELP(":<socks-server>:<host>:<port>") };
const struct addrdesc addr_socks4a_connect = { "socks4a", 3, xioopen_socks4_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, 1, 0, 0 HELP(":<socks-server>:<host>:<port>") }; const union xioaddr_desc *xioaddrs_socks4_connect[] = {
(union xioaddr_desc *)&xiointer_socks4_connect2,
(union xioaddr_desc *)&xioendpoint_socks4_connect3,
NULL
};
static const struct xioaddr_inter_desc xiointer_socks4a_connect2 = { XIOADDR_INTER, "socks4a", 2, XIOBIT_ALL, GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socks4_connect, 1, 0, 0, XIOBIT_RDWR HELP(":<host>:<port>") };
static const struct xioaddr_endpoint_desc xioendpoint_socks4a_connect3 = { XIOADDR_ENDPOINT, "socks4a", 3, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socks4_connect, 1, 0, 0 HELP(":<socks-server>:<host>:<port>") };
const union xioaddr_desc *xioaddrs_socks4a_connect[] = {
(union xioaddr_desc *)&xiointer_socks4a_connect2,
(union xioaddr_desc *)&xioendpoint_socks4a_connect3,
NULL
};
/*!!! should be two different functions */
static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts, static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd, int xioflags, xiofile_t *xxfd,
unsigned groups, int socks4a, int dummy2, unsigned groups, int socks4a, int dummy2,
@ -46,7 +61,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
/* we expect the form: host:host:port */ /* we expect the form: host:host:port */
struct single *xfd = &xxfd->stream; struct single *xfd = &xxfd->stream;
struct opt *opts0 = NULL; struct opt *opts0 = NULL;
const char *sockdname; char *socksport; const char *sockdname; char *sockdport;
const char *targetname, *targetport; const char *targetname, *targetport;
int pf = PF_UNSPEC; int pf = PF_UNSPEC;
int ipproto = IPPROTO_TCP; int ipproto = IPPROTO_TCP;
@ -58,21 +73,36 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
bool needbind = false; bool needbind = false;
bool lowport = false; bool lowport = false;
unsigned char buff[BUFF_LEN]; unsigned char buff[BUFF_LEN];
struct socks4 *sockhead = (struct socks4 *)buff; struct socks4request *sockhead = (struct socks4request *)buff;
size_t buflen = sizeof(buff); size_t buflen = sizeof(buff);
int socktype = SOCK_STREAM; int socktype = SOCK_STREAM;
int level; int level;
int result; int result;
if (argc != 4) { if (argc < 3 || argc > 4) {
Error1("%s: 3 parameters required", argv[0]); Warn("syntax 1 (terminal): socks-connect:<socks-server>:<host>:<port>");
Error("syntax 2 (inter): socks-connect:<host>:<port>");
return STAT_NORETRY;
}
if (argc == 3) {
if (xfd->fd1 < 0) {
Error("xioopen_socks4_connect(): socksservername missing");
return STAT_NORETRY;
}
sockdname = NULL;
targetname = argv[1];
targetport = argv[2];
} else /* if (argc == 4) */ {
if (xfd->fd1 >= 0) {
Error("xioopen_socks4_connect(): socksservername not allowed here");
return STAT_NORETRY; return STAT_NORETRY;
} }
sockdname = argv[1]; sockdname = argv[1];
targetname = argv[2]; targetname = argv[2];
targetport = argv[3]; targetport = argv[3];
}
xfd->howtoend = END_SHUTDOWN;
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
@ -80,20 +110,26 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
retropt_bool(opts, OPT_FORK, &dofork); retropt_bool(opts, OPT_FORK, &dofork);
result = _xioopen_socks4_prepare(targetport, opts, &socksport, sockhead, &buflen); result = _xioopen_socks4_prepare(targetport, opts, &sockdport, sockhead, &buflen);
if (result != STAT_OK) return result; if (result != STAT_OK) return result;
if (xfd->fd2 < 0) {
result = result =
_xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport, _xioopen_ipapp_prepare(opts, &opts0, sockdname, sockdport,
&pf, ipproto, &pf, ipproto,
xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[1],
xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.res_opts[0],
them, &themlen, us, &uslen, them, &themlen, us, &uslen,
&needbind, &lowport, &socktype); &needbind, &lowport, &socktype);
if (result != STAT_OK) return result;
Notice5("opening connection to %s:%u via socks4 server %s:%s as user \"%s\"", Notice5("opening connection to %s:%u via socks4 server %s:%s as user \"%s\"",
targetname, targetname,
ntohs(sockhead->port), ntohs(sockhead->port),
sockdname, socksport, sockhead->userid); sockdname, sockdport, sockhead->userid);
} else {
Notice3("opening connection to %s:%u using socks4 connect as user \"%s\"",
targetname, ntohs(sockhead->port), sockhead->userid);
}
do { /* loop over failed connect and socks-request attempts */ do { /* loop over failed connect and socks-request attempts */
@ -123,6 +159,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
return result; return result;
} }
if (xfd->fd2 < 0) {
/* this cannot fork because we retrieved fork option above */ /* this cannot fork because we retrieved fork option above */
result = result =
_xioopen_connect (xfd, _xioopen_connect (xfd,
@ -142,8 +179,14 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
default: default:
return result; return result;
} }
xfd->fdtype = FDTYPE_SINGLE;
} else {
xfd->dtype = XIODATA_STREAM;
xfd->fdtype = FDTYPE_DOUBLE;
}
applyopts(xfd->fd, opts, PH_ALL); /*!*/
applyopts(xfd->fd1, opts, PH_ALL);
if ((result = _xio_openlate(xfd, opts)) < 0) if ((result = _xio_openlate(xfd, opts)) < 0)
return result; return result;
@ -190,7 +233,8 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
} }
/* parent process */ /* parent process */
Notice1("forked off child process "F_pid, pid); Notice1("forked off child process "F_pid, pid);
Close(xfd->fd); Close(xfd->fd1);
Close(xfd->fd2);
Nanosleep(&xfd->intervall, NULL); Nanosleep(&xfd->intervall, NULL);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
continue; continue;
@ -205,7 +249,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
} }
int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **socksport, struct socks4 *sockhead, size_t *headlen) { int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **socksport, struct socks4request *sockhead, size_t *headlen) {
struct servent *se; struct servent *se;
char *userid; char *userid;
@ -247,7 +291,7 @@ int
_xioopen_socks4_connect0(struct single *xfd, _xioopen_socks4_connect0(struct single *xfd,
const char *hostname, /* socks target host */ const char *hostname, /* socks target host */
int socks4a, int socks4a,
struct socks4 *sockhead, struct socks4request *sockhead,
ssize_t *headlen, /* get available space, ssize_t *headlen, /* get available space,
return used length*/ return used length*/
int level) { int level) {
@ -294,15 +338,18 @@ int
/* perform socks4 client dialog on existing FD. /* perform socks4 client dialog on existing FD.
Called within fork/retry loop, after connect() */ Called within fork/retry loop, after connect() */
int _xioopen_socks4_connect(struct single *xfd, int _xioopen_socks4_connect(struct single *xfd,
struct socks4 *sockhead, struct socks4request *sockhead,
size_t headlen, size_t headlen,
int level) { int level) {
ssize_t bytes; ssize_t bytes;
int wfd;
int result; int result;
unsigned char buff[SIZEOF_STRUCT_SOCKS4]; unsigned char buff[SIZEOF_STRUCT_SOCKS4];
struct socks4 *replyhead = (struct socks4 *)buff; struct socks4head *replyhead = (struct socks4head *)buff;
char *destdomname = NULL; char *destdomname = NULL;
wfd = (xfd->fdtype == FDTYPE_SINGLE ? xfd->fd1 : xfd->fd2);
/* send socks header (target addr+port, +auth) */ /* send socks header (target addr+port, +auth) */
#if WITH_MSGLEVEL <= E_INFO #if WITH_MSGLEVEL <= E_INFO
if (ntohl(sockhead->dest) <= 0x000000ff) { if (ntohl(sockhead->dest) <= 0x000000ff) {
@ -329,13 +376,16 @@ int _xioopen_socks4_connect(struct single *xfd,
} }
#endif /* WITH_MSGLEVEL <= E_DEBUG */ #endif /* WITH_MSGLEVEL <= E_DEBUG */
do { do {
result = Write(xfd->fd, sockhead, headlen); result = Write(wfd, sockhead, headlen);
} while (result < 0 && errno == EINTR); } while (result < 0 && errno == EINTR);
if (result < 0) { if (result < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s", Msg4(level, "write(%d, %p, "F_Zu"): %s",
xfd->fd, sockhead, headlen, strerror(errno)); wfd, sockhead, headlen, strerror(errno));
if (Close(xfd->fd) < 0) { if (Close(wfd) < 0) {
Info2("close(%d): %s", xfd->fd, strerror(errno)); Info2("close(%d): %s", wfd, strerror(errno));
}
if (Close(xfd->fd1) < 0) {
Info2("close(%d): %s", xfd->fd1, strerror(errno));
} }
return STAT_RETRYLATER; /* retry complete open cycle */ return STAT_RETRYLATER; /* retry complete open cycle */
} }
@ -345,20 +395,26 @@ int _xioopen_socks4_connect(struct single *xfd,
while (bytes >= 0) { /* loop over answer chunks until complete or error */ while (bytes >= 0) { /* loop over answer chunks until complete or error */
/* receive socks answer */ /* receive socks answer */
do { do {
result = Read(xfd->fd, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes); result = Read(xfd->fd1, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes);
} while (result < 0 && errno == EINTR); } while (result < 0 && errno == EINTR);
if (result < 0) { if (result < 0) {
Msg4(level, "read(%d, %p, "F_Zu"): %s", Msg4(level, "read(%d, %p, "F_Zu"): %s",
xfd->fd, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes, xfd->fd1, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes,
strerror(errno)); strerror(errno));
if (Close(xfd->fd) < 0) { if (Close(xfd->fd1) < 0) {
Info2("close(%d): %s", xfd->fd, strerror(errno)); Info2("close(%d): %s", xfd->fd1, strerror(errno));
}
if (Close(wfd) < 0) {
Info2("close(%d): %s", wfd, strerror(errno));
} }
} }
if (result == 0) { if (result == 0) {
Msg(level, "read(): EOF during read of socks reply, peer might not be a socks4 server"); Msg(level, "read(): EOF during read of socks reply, peer might not be a socks4 server");
if (Close(xfd->fd) < 0) { if (Close(xfd->fd1) < 0) {
Info2("close(%d): %s", xfd->fd, strerror(errno)); Info2("close(%d): %s", xfd->fd1, strerror(errno));
}
if (Close(wfd) < 0) {
Info2("close(%d): %s", wfd, strerror(errno));
} }
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }

View file

@ -1,36 +1,37 @@
/* $Id: xio-socks.h,v 1.6 2004/06/06 19:03:28 gerhard Exp $ */ /* $Id: xio-socks.h,v 1.6.2.1 2006/07/24 19:18:30 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2004 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_socks_h_included #ifndef __xio_socks_h_included
#define __xio_socks_h_included 1 #define __xio_socks_h_included 1
struct socks4 { #define SIZEOF_STRUCT_SOCKS4 sizeof(struct socks4head)
struct socks4request {
uint8_t version; uint8_t version;
uint8_t action; uint8_t action;
uint16_t port; uint16_t port;
uint32_t dest; uint32_t dest;
char userid[1]; /* just to have access via this struct */ char userid[1]; /* just to have access via this struct */
} ; } ;
#define SIZEOF_STRUCT_SOCKS4 8
extern const struct optdesc opt_socksport; extern const struct optdesc opt_socksport;
extern const struct optdesc opt_socksuser; extern const struct optdesc opt_socksuser;
extern const struct addrdesc addr_socks4_connect; extern const union xioaddr_desc *xioaddrs_socks4_connect[];
extern const struct addrdesc addr_socks4a_connect; extern const union xioaddr_desc *xioaddrs_socks4a_connect[];
extern int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **socksport, struct socks4 *sockhead, size_t *headlen); extern int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **socksport, struct socks4request *sockhead, size_t *headlen);
extern int extern int
_xioopen_socks4_connect0(struct single *xfd, _xioopen_socks4_connect0(struct single *xfd,
const char *hostname, /* socks target host */ const char *hostname, /* socks target host */
int socks4a, int socks4a,
struct socks4 *sockhead, struct socks4request *sockhead,
ssize_t *headlen, /* get available space, ssize_t *headlen, /* get available space,
return used length*/ return used length*/
int level); int level);
extern int _xioopen_socks4_connect(struct single *xfd, extern int _xioopen_socks4_connect(struct single *xfd,
struct socks4 *sockhead, struct socks4request *sockhead,
size_t headlen, size_t headlen,
int level); int level);

505
xio-socks5.c Normal file
View file

@ -0,0 +1,505 @@
/* $Id$ */
/* Copyright Gerhard Rieger 2004-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of socks5 type */
#include "xiosysincludes.h"
#include "xioopen.h"
#include "xio-socket.h"
#include "xio-ipapp.h"
#include "xio-socks5.h"
#if WITH_SOCKS5
#define SOCKSPORT "1080"
#define SOCKS5_MAXLEN 512
static int
xioopen_socks5_client(int argc, const char *argv[],
struct opt *opts, int xioflags, xiofile_t *xfd,
unsigned groups, int dummy1, int dummy2,
int dummy3);
const struct optdesc opt_socks5_username = { "socks5-username", "socks5user", OPT_SOCKS5_USERNAME, GROUP_SOCKS5, PH_LATE, TYPE_STRING, OFUNC_SPEC };
const struct optdesc opt_socks5_password = { "socks5-password", "socks5pass", OPT_SOCKS5_PASSWORD, GROUP_SOCKS5, PH_LATE, TYPE_STRING, OFUNC_SPEC };
static const struct xioaddr_inter_desc xiointer_socks5_client = { XIOADDR_PROT, "socks5", 2, XIOBIT_ALL, GROUP_SOCKS5, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socks5_client, 0, 0, 0, XIOBIT_RDWR HELP(":<host>:<port>") };
const union xioaddr_desc *xioaddrs_socks5_client[] = {
(union xioaddr_desc *)&xiointer_socks5_client, NULL };
/* read until buflen bytes received or EOF */
/* returns STAT_OK, STAT_RETRYLATER, or STAT_NOTRETRY */
static int xiosocks5_recvbytes(struct single *xfd,
uint8_t *buff, size_t buflen, int level) {
size_t bytes;
ssize_t result;
bytes = 0;
while (bytes >= 0) { /* loop over answer chunks until complete or error */
/* receive socks answer */
Debug("waiting for data from peer");
do {
result = Read(xfd->fd1, buff+bytes, buflen-bytes);
} while (result < 0 && errno == EINTR);
if (result < 0) {
Msg4(level, "read(%d, %p, "F_Zu"): %s",
xfd->fd1, buff+bytes, buflen-bytes,
strerror(errno));
if (Close(xfd->fd1) < 0) {
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
}
if (Close(xfd->fd2) < 0) {
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
}
return STAT_RETRYLATER;
}
if (result == 0) {
Msg(level, "read(): EOF during read of socks reply");
if (Close(xfd->fd1) < 0) {
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
}
if (Close(xfd->fd2) < 0) {
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
}
return STAT_RETRYLATER;
}
bytes += result;
if (bytes == buflen) {
Debug1("received all "F_Zd" bytes", bytes);
break;
}
Debug2("received "F_Zd" bytes, waiting for "F_Zu" more bytes",
result, buflen-bytes);
}
if (result <= 0) { /* we had a problem while reading socks answer */
return STAT_RETRYLATER; /* retry complete open cycle */
}
return STAT_OK;
}
static int xioopen_socks5_client(int argc, const char *argv[],
struct opt *opts, int xioflags,
xiofile_t *xxfd,
unsigned groups, int dummy1, int dummy2,
int dummy3) {
/* we expect the form: host:port */
xiosingle_t *xfd = &xxfd->stream;
const char *targetname, *targetservice;
int level;
int result;
if (argc != 3) {
Error("SOCKS5 syntax: socks5-connect:<host>:<port>"); /*! UDP? */
return STAT_NORETRY;
}
targetname = argv[1];
targetservice = argv[2];
applyopts(-1, opts, PH_INIT);
applyopts_single(xfd, opts, PH_INIT);
#if 0
result = _xioopen_socks5_prepare(a3, opts, &socksport, sockhead, &buflen);
if (result != STAT_OK) return result;
#endif
if (xfd->fd1 < 0) {
Error("socks5 must be used as embedded address");
return -1;
}
Notice2("opening connection to %s:%s using socks5",
targetname, targetservice);
do { /* loop over failed connect and socks-request attempts */
#if WITH_RETRY
if (xfd->forever || xfd->retry) {
level = E_INFO;
} else
#endif /* WITH_RETRY */
level = E_ERROR;
#if 0
/* we try to resolve the target address _before_ connecting to the socks
server: this avoids unnecessary socks connects and timeouts */
result =
_xioopen_socks5_connect0(xfd, targetname, sockhead, opts,
(ssize_t *)&buflen, level);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (xfd->forever || xfd->retry--) {
if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL);
continue;
}
#endif /* WITH_RETRY */
default:
return result;
}
#endif
#if 0
if (xfd->fd1 < 0) {
/* this cannot fork because we retrieved fork option above */
result =
_xioopen_connect (xfd,
needbind?(struct sockaddr *)us:NULL, sizeof(*us),
(struct sockaddr *)them, sizeof(struct sockaddr_in),
opts, PF_INET, socktype, IPPROTO_TCP, lowport, level);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (xfd->forever || xfd->retry--) {
if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL);
continue;
}
#endif /* WITH_RETRY */
default:
return result;
}
xfd->fd1 = xfd->fd2 = xfd->fd;
} else
#endif
xfd->dtype = XIODATA_STREAM;
result =
_xioopen_socks5_connect(xfd, targetname, targetservice, opts, level);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (xfd->forever || xfd->retry--) {
if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL);
continue;
}
#endif /* WITH_RETRY */
default:
return result;
}
/*!*/
applyopts(xfd->fd1, opts, PH_ALL);
if ((result = _xio_openlate(xfd, opts)) < 0)
return result;
{
break;
}
} while (true); /* end of complete open loop - drop out on success */
return 0;
}
/* perform socks5 client dialog on existing FD.
Called within fork/retry loop, after connect() */
int _xioopen_socks5_connect(struct single *xfd,
const char *targetname, const char *targetservice,
struct opt *opts, int level) {
uint16_t targetport;
unsigned char sendbuff[SOCKS5_MAXLEN]; size_t sendlen;
unsigned char recvbuff[SOCKS5_MAXLEN];
struct socks5_method *sendmethod;
struct socks5_select *recvselect;
struct socks5_request *sendrequest;
struct socks5_reply *recvreply;
size_t namelen;
size_t addrlen;
size_t readpos;
char *emsg;
int result;
/* prepare */
targetport = parseport(targetservice, IPPROTO_TCP/*!*/);
/* just the simplest authentications */
sendmethod = (struct socks5_method *)sendbuff;
sendmethod->version = 5; /* protocol version */
sendmethod->nmethods = 2; /* number of proposed authentication types */
sendmethod->methods[0] = SOCKS5_METHOD_NOAUTH; /* no auth at all */
sendmethod->methods[1] = SOCKS5_METHOD_USERPASS; /* username/password */
/*sendmethod->methods[2] = SOCKS5_METHOD_AVENTAIL;*/ /* Aventail Connect */
sendlen = 2+sendmethod->nmethods;
/* send socks header (target addr+port, +auth) */
Info("sending socks5 identifier/method selection message");
do {
result = Write(xfd->fd2, sendmethod, sendlen);
} while (result < 0 && errno == EINTR);
if (result < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s",
xfd->fd2, sendmethod, sendlen, strerror(errno));
if (Close(xfd->fd2) < 0) {
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
}
if (Close(xfd->fd1) < 0) {
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
}
return STAT_RETRYLATER; /* retry complete open cycle */
}
Info1("waiting for socks5 select reply ("F_Zu" bytes)", SOCKS5_SELECT_LENGTH);
if ((result =
xiosocks5_recvbytes(xfd, recvbuff, SOCKS5_SELECT_LENGTH, level)) !=
STAT_OK) {
/* we had a problem while reading socks answer */
/*! Close(); */
return result; /* ev. retry complete open cycle */
}
recvselect = (struct socks5_select *)recvbuff;
Info2("socks5 select: {%u, %u}", recvselect->version, recvselect->method);
if (recvselect->version != 5) {
Error1("socks5: server protocol version is %u",
recvbuff[0]);
}
if (recvselect->method == SOCKS5_METHOD_NONE) {
Error("socks5: server did not accept our authentication methods");
}
/*! check if selected methods is one of our proposals */
switch (recvselect->method) {
case SOCKS5_METHOD_NOAUTH:
break;
case SOCKS5_METHOD_USERPASS:
if (xio_socks5_username_password(level, opts, xfd) < 0) {
Error("username/password not accepted");
}
break;
default:
Error("socks5 select: unimplemented authentication method selected");
break;
}
sendrequest = (struct socks5_request *)sendbuff;
sendrequest->version = SOCKS5_VERSION;
sendrequest->command = SOCKS5_COMMAND_CONNECT;
sendrequest->reserved = 0;
sendrequest->addrtype = SOCKS5_ADDRTYPE_NAME;
switch (sendrequest->addrtype) {
case SOCKS5_ADDRTYPE_IPV4:
break;
case SOCKS5_ADDRTYPE_NAME:
if ((namelen = strlen(targetname)) > 255) {
Error1("socks5: target name is longer than 255 bytes: \"%s\"",
targetname);
}
sendrequest->destaddr[0] = strlen(targetname);
strncpy(sendrequest->destaddr+1, targetname, sizeof(sendbuff)-5);
break;
case SOCKS5_ADDRTYPE_IPV6:
break;
default: Fatal("socks5: undefined address type in socks request");
}
*((uint16_t *)&sendrequest->destaddr[strlen(targetname)+1]) = targetport;
sendlen = sizeof(struct socks5_request) + namelen + 2;
/* send socks request (target addr+port, +auth) */
Info("sending socks5 request selection");
do {
result = Write(xfd->fd2, sendrequest, sendlen);
} while (result < 0 && errno == EINTR);
if (result < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s",
xfd->fd2, sendmethod, sendlen, strerror(errno));
if (Close(xfd->fd2) < 0) {
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
}
if (Close(xfd->fd1) < 0) {
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
}
return STAT_RETRYLATER; /* retry complete open cycle */
}
Info("waiting for socks5 reply");
recvreply = (struct socks5_reply *)recvbuff;
if ((result =
xiosocks5_recvbytes(xfd, recvbuff, SOCKS5_REPLY_LENGTH1, level))
!= STAT_OK) {
/*! close... */
return result;
}
if (recvreply->version != SOCKS5_VERSION) {
Error1("socks5: version of reply is %d", recvreply->version);
}
switch (recvreply->reply) {
case SOCKS5_REPLY_SUCCESS: emsg = NULL; break;
case SOCKS5_REPLY_FAILURE: emsg = "general socks server failure"; break;
case SOCKS5_REPLY_DENIED: emsg = "connection not allowed by ruleset"; break;
case SOCKS5_REPLY_NETUNREACH: emsg = "network unreachable"; break;
case SOCKS5_REPLY_HOSTUNREACH: emsg = "host unreachable"; break;
case SOCKS5_REPLY_REFUSED: emsg = "connection refused"; break;
case SOCKS5_REPLY_TTLEXPIRED: emsg = "TTL expired"; break;
case SOCKS5_REPLY_CMDUNSUPP: emsg = "command not supported"; break;
case SOCKS5_REPLY_ADDRUNSUPP: emsg = "address type not supported"; break;
default: emsg = "undefined error code"; break;
}
if (recvreply->reply != SOCKS5_REPLY_SUCCESS) {
Error1("socks5 reply: %s", emsg);
}
switch (recvreply->addrtype) {
case SOCKS5_ADDRTYPE_IPV4:
addrlen = 4; /*!*/
if ((result =
xiosocks5_recvbytes(xfd, recvbuff+SOCKS5_REPLY_LENGTH1, addrlen,
level))
!= STAT_OK) {
/*! close... */
return result;
}
readpos = sizeof(recvreply)-1+4;
break;
case SOCKS5_ADDRTYPE_NAME:
/* read 1 byte containing domain name length */
if ((result =
xiosocks5_recvbytes(xfd, recvbuff+SOCKS5_REPLY_LENGTH1, 1, level))
!= STAT_OK) {
/*! close... */
return result;
}
/* read domain name */
if ((result =
xiosocks5_recvbytes(xfd, recvbuff+SOCKS5_REPLY_LENGTH1+1,
recvreply->destaddr[0], level))
!= STAT_OK) {
/*! close... */
return result;
}
readpos = sizeof(recvreply)+recvreply->destaddr[0];
addrlen = recvreply->destaddr[0]+1;
break;
case SOCKS5_ADDRTYPE_IPV6:
addrlen = 16; /*!*/
if ((result =
xiosocks5_recvbytes(xfd, recvbuff+SOCKS5_REPLY_LENGTH1, addrlen,
level))
== EOF) {
/*! close... */
return result;
}
readpos = sizeof(recvreply)-1+4;
break;
default: Error("socks5: undefined address type in answer");
addrlen = 0;
readpos = sizeof(recvreply)-1;
}
if ((result =
xiosocks5_recvbytes(xfd, recvbuff+readpos, 2, level))
!= STAT_OK) {
/*! close... */
return result;
}
/*! Infos(...); */
return STAT_OK;
}
int xio_socks5_username_password(int level, struct opt *opts,
struct single *xfd) {
/*!!! */
unsigned char sendbuff[513];
unsigned char *pos;
char *username = NULL;
char *password = NULL;
unsigned char recvbuff[2];
struct socks5_userpass_reply *reply;
int result;
retropt_string(opts, OPT_SOCKS5_USERNAME, (char **)&username);
if (username == NULL) {
Error("socks5: username required");
return STAT_NORETRY;
}
retropt_string(opts, OPT_SOCKS5_PASSWORD, (char **)&password);
if (password == NULL) {
Error("socks5: password required");
return STAT_NORETRY;
}
pos = sendbuff;
*pos++ = SOCKS5_USERPASS_VERSION;
*pos++ = strlen(username);
strncpy(pos, username, 255);
pos += strlen(username);
*pos++ = strlen(password);
strncpy(pos, password, 255);
pos += strlen(password);
result =
xio_socks5_dialog(level, xfd, sendbuff, pos-sendbuff,
recvbuff, 2,
"username/password authentication");
if (result != STAT_OK) {
Msg(level, "socks5 username/password dialog failed");
return result;
}
Info("socks5 username/password authentication succeeded");
reply = (struct socks5_userpass_reply *)recvbuff;
if (reply->version != SOCKS5_USERPASS_VERSION) {
Msg(level, "socks5 username/password authentication version mismatch");
return STAT_NORETRY;
}
if (reply->status != SOCKS5_REPLY_SUCCESS) {
Msg(level, "socks5 username/password authentication failure");
return STAT_RETRYLATER;
}
return STAT_OK;
}
int xio_socks5_dialog(int level, struct single *xfd,
unsigned char *sendbuff, size_t sendlen,
unsigned char *recvbuff, size_t recvlen,
const char *descr /* identifier/method selection */) {
int result;
/* send socks header (target addr+port, +auth) */
Info1("sending socks5 %s message", descr);
do {
result = Write(xfd->fd2, sendbuff, sendlen);
} while (result < 0 && errno == EINTR);
if (result < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s",
xfd->fd2, sendbuff, sendlen, strerror(errno));
if (Close(xfd->fd2) < 0) {
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
}
if (Close(xfd->fd1) < 0) {
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
}
return STAT_RETRYLATER; /* retry complete open cycle */
}
Info2("waiting for socks5 %s reply ("F_Zu" bytes)",
descr, recvlen);
if ((result =
xiosocks5_recvbytes(xfd, recvbuff, recvlen, level))
== EOF) {
/* we had a problem while reading socks answer */
/*! Close(); */
return result; /* retry complete open cycle */
}
#if 0
replyversion = ((struct socks5_version *)recvbuff)->version;
Info1("socks5 server reply version: {%u}", replyversion);
if (replyversion != SOCKS5_VERSION) {
Error1("socks5: server protocol version is %u",
replyversion);
}
#endif
return 0;
}
#endif /* WITH_SOCKS5 */

107
xio-socks5.h Normal file
View file

@ -0,0 +1,107 @@
/* $Id$ */
/* Copyright Gerhard Rieger 2004-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_socks5_h_included
#define __xio_socks5_h_included 1
#define SOCKS5_VERSION 5
#define SOCKS5_METHOD_NOAUTH 0x00
#define SOCKS5_METHOD_GSSAPI 0x01
#define SOCKS5_METHOD_USERPASS 0x02
#define SOCKS5_METHOD_AVENTAIL 0x86 /*!*/
#define SOCKS5_METHOD_NONE 0xff
#define SOCKS5_COMMAND_CONNECT 0x01
#define SOCKS5_COMMAND_BIND 0x02
#define SOCKS5_COMMAND_UDPASSOC 0x03
#define SOCKS5_ADDRTYPE_IPV4 0x01
#define SOCKS5_ADDRTYPE_NAME 0x03
#define SOCKS5_ADDRTYPE_IPV6 0x04
#define SOCKS5_REPLY_SUCCESS 0x00
#define SOCKS5_REPLY_FAILURE 0x01
#define SOCKS5_REPLY_DENIED 0x02
#define SOCKS5_REPLY_NETUNREACH 0x03
#define SOCKS5_REPLY_HOSTUNREACH 0x04
#define SOCKS5_REPLY_REFUSED 0x05
#define SOCKS5_REPLY_TTLEXPIRED 0x06
#define SOCKS5_REPLY_CMDUNSUPP 0x07
#define SOCKS5_REPLY_ADDRUNSUPP 0x08
#define SOCKS5_USERPASS_VERSION 0x01
/* just the first byte of server replies */
struct socks5_version {
uint8_t version;
} ;
/* the version/method selection message of the client */
struct socks5_method {
uint8_t version;
uint8_t nmethods;
uint8_t methods[1]; /* has variable length, see nmethods */
} ;
/* the selection message of the server */
struct socks5_select {
uint8_t version;
uint8_t method;
} ;
#define SOCKS5_SELECT_LENGTH sizeof(struct socks5_select)
/* the request message */
struct socks5_request {
uint8_t version;
uint8_t command;
uint8_t reserved;
uint8_t addrtype;
uint8_t destaddr[1]; /* has variable length */
/*uint16_t destport;*/ /* position depends on length of destaddr */
} ;
/* the request message */
struct socks5_reply {
uint8_t version;
uint8_t reply;
uint8_t reserved;
uint8_t addrtype;
uint8_t destaddr[1]; /* has variable length */
/*uint16_t destport;*/ /* position depends on length of destaddr */
} ;
#define SOCKS5_REPLY_LENGTH1 4 /*!*/ /* the fixed size fields */
/* the username/password authentication reply */
struct socks5_userpass_reply {
uint8_t version; /* authentication version, not socks version */
uint8_t status;
} ;
#if 0
extern const struct optdesc opt_socksport;
extern const struct optdesc opt_socksuser;
#endif
extern const struct optdesc opt_socks5_username;
extern const struct optdesc opt_socks5_password;
extern const union xioaddr_desc *xioaddrs_socks5_client[];
extern int
_xioopen_socks5_connect0(struct single *xfd,
const char *targetname, const char *targetservice,
int level);
extern int _xioopen_socks5_connect(struct single *xfd,
const char *targetname,
const char *targetservice,
struct opt *opts,
int level);
extern int xio_socks5_dialog(int level, struct single *xfd,
unsigned char *sendbuff, size_t sendlen,
unsigned char *recvbuff, size_t recvlen,
const char *descr);
extern int xio_socks5_username_password(int level, struct opt *opts,
struct single *xfd);
#endif /* !defined(__xio_socks5_h_included) */

View file

@ -1,5 +1,5 @@
/* $Id: xio-stdio.c,v 1.18 2006/12/28 14:07:01 gerhard Exp $ */ /* $Id: xio-stdio.c,v 1.18 2006/12/28 14:07:01 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses stdio type */ /* this file contains the source for opening addresses stdio type */
@ -20,49 +20,51 @@ static int xioopen_stdfd(int argc, const char *argv[], struct opt *opts, int xio
/* we specify all option groups that we can imagine for a FD, becasue the /* we specify all option groups that we can imagine for a FD, becasue the
changed parsing mechanism does not allow us to check the type of FD before changed parsing mechanism does not allow us to check the type of FD before
applying the options */ applying the options */
const struct addrdesc addr_stdio = { "stdio", 3, xioopen_stdio, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 0, 0, 0 HELP(NULL) }; static const struct xioaddr_endpoint_desc xioaddr_stdio0 = { XIOADDR_SYS, "stdio", 0, XIOBIT_ALL, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_stdio, 0, 0, 0 HELP(NULL) };
const struct addrdesc addr_stdin = { "stdin", 1, xioopen_stdfd, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 0, 0, 0 HELP(NULL) }; static const struct xioaddr_endpoint_desc xioaddr_stdin0 = { XIOADDR_SYS, "stdin", 0, XIOBIT_RDONLY, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_stdfd, 0, 0, 0 HELP(NULL) };
const struct addrdesc addr_stdout = { "stdout", 2, xioopen_stdfd, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 1, 0, 0 HELP(NULL) }; static const struct xioaddr_endpoint_desc xioaddr_stdout0 = { XIOADDR_SYS, "stdout", 0, XIOBIT_WRONLY, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_stdfd, 1, 0, 0 HELP(NULL) };
const struct addrdesc addr_stderr = { "stderr", 2, xioopen_stdfd, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 2, 0, 0 HELP(NULL) }; static const struct xioaddr_endpoint_desc xioaddr_stderr0 = { XIOADDR_SYS, "stderr", 0, XIOBIT_WRONLY, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_stdfd, 2, 0, 0 HELP(NULL) };
const union xioaddr_desc *xioaddrs_stdio[] = {
(union xioaddr_desc *)&xioaddr_stdio0, NULL };
const union xioaddr_desc *xioaddrs_stdin[] = {
(union xioaddr_desc *)&xioaddr_stdin0, NULL };
const union xioaddr_desc *xioaddrs_stdout[] = {
(union xioaddr_desc *)&xioaddr_stdout0, NULL };
const union xioaddr_desc *xioaddrs_stderr[] = {
(union xioaddr_desc *)&xioaddr_stderr0, NULL };
/* process a bidirectional "stdio" or "-" argument with options. /* process a bidirectional "stdio" or "-" argument with options.
generate a dual address. */ generate a dual address. */
int xioopen_stdio_bi(xiofile_t *sock) { int xioopen_stdio_bi(xiofile_t *sock) {
struct opt *opts1, *opts2, *optspr; struct opt *opts1, *opts2, *optspr;
unsigned int groups1 = addr_stdio.groups, groups2 = addr_stdio.groups; unsigned int groups1 = xioaddr_stdio0.groups, groups2 = xioaddr_stdio0.groups;
int result; int result;
if (xioopen_makedual(sock) < 0) { sock->stream.fd1 = 0 /*stdin*/;
return -1; sock->stream.fd2 = 1 /*stdout*/;
} sock->stream.fdtype = FDTYPE_DOUBLE;
sock->dual.stream[0]->tag = XIO_TAG_RDONLY;
sock->dual.stream[0]->fd = 0 /*stdin*/;
sock->dual.stream[1]->tag = XIO_TAG_WRONLY;
sock->dual.stream[1]->fd = 1 /*stdout*/;
sock->dual.stream[0]->howtoend =
sock->dual.stream[1]->howtoend = END_NONE;
#if WITH_TERMIOS #if WITH_TERMIOS
if (Isatty(sock->dual.stream[0]->fd)) { if (Isatty(sock->stream.fd1)) {
if (Tcgetattr(sock->dual.stream[0]->fd, if (Tcgetattr(sock->stream.fd1,
&sock->dual.stream[0]->savetty) &sock->stream.savetty)
< 0) { < 0) {
Warn2("cannot query current terminal settings on fd %d: %s", Warn2("cannot query current terminal settings on fd %d: %s",
sock->dual.stream[0]->fd, strerror(errno)); sock->stream.fd1, strerror(errno));
} else { } else {
sock->dual.stream[0]->ttyvalid = true; sock->stream.ttyvalid = true;
} }
} }
if (Isatty(sock->dual.stream[1]->fd)) { if (Isatty(sock->stream.fd2)) {
if (Tcgetattr(sock->dual.stream[1]->fd, if (Tcgetattr(sock->stream.fd2,
&sock->dual.stream[1]->savetty) &sock->stream.savetty)
< 0) { < 0) {
Warn2("cannot query current terminal settings on fd %d: %s", Warn2("cannot query current terminal settings on fd %d: %s",
sock->dual.stream[1]->fd, strerror(errno));
sock->stream.fd2, strerror(errno));
} else { } else {
sock->dual.stream[1]->ttyvalid = true; sock->stream.ttyvalid = true;
} }
} }
#endif /* WITH_TERMIOS */ #endif /* WITH_TERMIOS */
@ -71,7 +73,7 @@ int xioopen_stdio_bi(xiofile_t *sock) {
applyopts(-1, sock->stream.opts, PH_INIT); applyopts(-1, sock->stream.opts, PH_INIT);
/* options here are one-time and one-direction, no second use */ /* options here are one-time and one-direction, no second use */
retropt_bool(sock->stream.opts, OPT_IGNOREEOF, &sock->dual.stream[0]->ignoreeof); retropt_bool(sock->stream.opts, OPT_IGNOREEOF, &sock->stream.ignoreeof);
/* extract opts that should be applied only once */ /* extract opts that should be applied only once */
if ((optspr = copyopts(sock->stream.opts, GROUP_PROCESS)) == NULL) { if ((optspr = copyopts(sock->stream.opts, GROUP_PROCESS)) == NULL) {
@ -88,10 +90,10 @@ int xioopen_stdio_bi(xiofile_t *sock) {
} }
/* apply options to first FD */ /* apply options to first FD */
if ((result = applyopts(sock->dual.stream[0]->fd, opts1, PH_ALL)) < 0) { if ((result = applyopts(sock->stream.fd1, opts1, PH_ALL)) < 0) {
return result; return result;
} }
if ((result = _xio_openlate(sock->dual.stream[0], opts1)) < 0) { if ((result = _xio_openlate(&sock->stream, opts1)) < 0) {
return result; return result;
} }
@ -99,14 +101,14 @@ int xioopen_stdio_bi(xiofile_t *sock) {
return -1; return -1;
} }
/* apply options to second FD */ /* apply options to second FD */
if ((result = applyopts(sock->dual.stream[1]->fd, opts2, PH_ALL)) < 0) { if ((result = applyopts(sock->stream.fd2, opts2, PH_ALL)) < 0) {
return result; return result;
} }
if ((result = _xio_openlate(sock->dual.stream[1], opts2)) < 0) { if ((result = _xio_openlate(&sock->stream, opts2)) < 0) {
return result; return result;
} }
if ((result = _xio_openlate(sock->dual.stream[1], optspr)) < 0) { if ((result = _xio_openlate(&sock->stream, optspr)) < 0) {
return result; return result;
} }
@ -131,7 +133,7 @@ static int xioopen_stdio(int argc, const char *argv[], struct opt *opts, int xio
Notice2("using %s for %s", Notice2("using %s for %s",
&("stdin\0\0\0stdout"[rw<<3]), &("stdin\0\0\0stdout"[rw<<3]),
ddirection[rw]); ddirection[rw]);
return xioopen_fd(opts, rw, &fd->stream, rw, dummy2, dummy3); return xioopen_fd(opts, rw, fd, rw, -1, dummy2, dummy3);
} }
/* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw. /* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw.
@ -145,6 +147,6 @@ static int xioopen_stdfd(int argc, const char *argv[], struct opt *opts, int xio
Notice2("using %s for %s", Notice2("using %s for %s",
&("stdin\0\0\0stdout\0\0stderr"[fd<<3]), &("stdin\0\0\0stdout\0\0stderr"[fd<<3]),
ddirection[rw]); ddirection[rw]);
return xioopen_fd(opts, rw, &xfd->stream, fd, dummy2, dummy3); return xioopen_fd(opts, rw, xfd, fd, -1, dummy2, dummy3);
} }
#endif /* WITH_STDIO */ #endif /* WITH_STDIO */

View file

@ -1,17 +1,16 @@
/* $Id: xio-stdio.h,v 1.5 2006/02/08 19:47:03 gerhard Exp $ */ /* $Id: xio-stdio.h,v 1.5.2.1 2006/07/24 19:18:35 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_stdio_h_included #ifndef __xio_stdio_h_included
#define __xio_stdio_h_included 1 #define __xio_stdio_h_included 1
extern int xioopen_stdio_bi(xiofile_t *sock); extern int xioopen_stdio_bi(xiofile_t *sock);
extern const struct addrdesc addr_stdio; extern const union xioaddr_desc *xioaddrs_stdio[];
extern const struct addrdesc addr_stdin; extern const union xioaddr_desc *xioaddrs_stdin[];
extern const struct addrdesc addr_stdout; extern const union xioaddr_desc *xioaddrs_stdout[];
extern const struct addrdesc addr_stderr; extern const union xioaddr_desc *xioaddrs_stderr[];
#endif /* !defined(__xio_stdio_h_included) */ #endif /* !defined(__xio_stdio_h_included) */

View file

@ -1,5 +1,5 @@
/* $Id: xio-system.c,v 1.13 2006/03/21 20:53:38 gerhard Exp $ */ /* $Id: xio-system.c,v 1.13.2.1 2006/07/24 19:18:36 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of system type */ /* this file contains the source for opening addresses of system type */
@ -20,8 +20,12 @@ static int xioopen_system(int arg, const char *argv[], struct opt *opts,
int dummy1, int dummy2, int dummy3 int dummy1, int dummy2, int dummy3
); );
const struct addrdesc addr_system = { "system", 3, xioopen_system, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, 1, 0, 0 HELP(":<shell-command>") }; static const struct xioaddr_endpoint_desc xioendpoint_system1 = { XIOADDR_SYS, "system", 1, XIOBIT_ALL, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_system, 1, 0, 0 HELP(":<shell-command>") };
const union xioaddr_desc *xioaddrs_system[] = {
(union xioaddr_desc *)&xioendpoint_system1,
NULL
};
static int xioopen_system(int argc, const char *argv[], struct opt *opts, static int xioopen_system(int argc, const char *argv[], struct opt *opts,
int xioflags, /* XIO_RDONLY etc. */ int xioflags, /* XIO_RDONLY etc. */
@ -34,7 +38,7 @@ static int xioopen_system(int argc, const char *argv[], struct opt *opts,
int result; int result;
const char *string = argv[1]; const char *string = argv[1];
status = _xioopen_foxec(xioflags, &fd->stream, groups, &opts); status = _xioopen_foxec_end(xioflags, &fd->stream, groups, &opts);
if (status < 0) return status; if (status < 0) return status;
if (status == 0) { /* child */ if (status == 0) { /* child */
int numleft; int numleft;

View file

@ -1,10 +1,10 @@
/* $Id: xio-system.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */ /* $Id: xio-system.h,v 1.4.2.1 2006/07/24 19:18:38 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_system_h_included #ifndef __xio_system_h_included
#define __xio_system_h_included 1 #define __xio_system_h_included 1
extern const struct addrdesc addr_system; extern const union xioaddr_desc *xioaddrs_system[];
#endif /* !defined(__xio_system_h_included) */ #endif /* !defined(__xio_system_h_included) */

View file

@ -1,5 +1,5 @@
/* $Id: xio-tcp.c,v 1.24 2006/07/13 06:48:47 gerhard Exp $ */ /* $Id: xio-tcp.c,v 1.24.2.1 2006/07/24 19:18:39 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for TCP related functions and options */ /* this file contains the source for TCP related functions and options */
@ -17,23 +17,29 @@
/****** TCP addresses ******/ /****** TCP addresses ******/
#if WITH_IP4 || WITH_IP6 #if WITH_IP4 || WITH_IP6
const struct addrdesc addr_tcp_connect = { "tcp-connect", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_UNSPEC HELP(":<host>:<port>") }; static const struct xioaddr_endpoint_desc xioendpoint_tcp_connect2 = { XIOADDR_SYS, "tcp-connect", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_connect, SOCK_STREAM, IPPROTO_TCP, PF_UNSPEC HELP(":<host>:<port>") };
const union xioaddr_desc *xioaddrs_tcp_connect[] = { (union xioaddr_desc *)&xioendpoint_tcp_connect2, NULL };
#if WITH_LISTEN #if WITH_LISTEN
const struct addrdesc addr_tcp_listen = { "tcp-listen", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_UNSPEC HELP(":<port>") }; static const struct xioaddr_endpoint_desc xioendpoint_tcp_listen1 = { XIOADDR_SYS, "tcp-listen", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_listen, SOCK_STREAM, IPPROTO_TCP, PF_UNSPEC HELP(":<port>") };
const union xioaddr_desc *xioaddrs_tcp_listen[] = { (union xioaddr_desc *)&xioendpoint_tcp_listen1, NULL };
#endif #endif
#endif #endif
#if WITH_IP4 #if WITH_IP4
const struct addrdesc addr_tcp4_connect = { "tcp4-connect", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_INET HELP(":<host>:<port>") }; static const struct xioaddr_endpoint_desc xioendpoint_tcp4_connect2 = { XIOADDR_SYS, "tcp4-connect", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_connect, SOCK_STREAM, IPPROTO_TCP, PF_INET HELP(":<host>:<port>") };
const union xioaddr_desc *xioaddrs_tcp4_connect[] = { (union xioaddr_desc *)&xioendpoint_tcp4_connect2, NULL };
#if WITH_LISTEN #if WITH_LISTEN
const struct addrdesc addr_tcp4_listen = { "tcp4-listen", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_INET HELP(":<port>") }; static const struct xioaddr_endpoint_desc xioendpoint_tcp4_listen1 = { XIOADDR_SYS, "tcp4-listen", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_listen, SOCK_STREAM, IPPROTO_TCP, PF_INET HELP(":<port>") };
const union xioaddr_desc *xioaddrs_tcp4_listen[] = { (union xioaddr_desc *)&xioendpoint_tcp4_listen1, NULL };
#endif #endif
#endif /* WITH_IP4 */ #endif /* WITH_IP4 */
#if WITH_IP6 #if WITH_IP6
const struct addrdesc addr_tcp6_connect = { "tcp6-connect", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_INET6 HELP(":<host>:<port>") }; static const struct xioaddr_endpoint_desc xioendpoint_tcp6_connect2 = { XIOADDR_SYS, "tcp6-connect", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_connect, SOCK_STREAM, IPPROTO_TCP, PF_INET6 HELP(":<host>:<port>") };
const union xioaddr_desc *xioaddrs_tcp6_connect[] = {(union xioaddr_desc *) &xioendpoint_tcp6_connect2, NULL };
#if WITH_LISTEN #if WITH_LISTEN
const struct addrdesc addr_tcp6_listen = { "tcp6-listen", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_INET6 HELP(":<port>") }; static const struct xioaddr_endpoint_desc xioendpoint_tcp6_listen1 = { XIOADDR_SYS, "tcp6-listen", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_listen, SOCK_STREAM, IPPROTO_TCP, PF_INET6 HELP(":<port>") };
const union xioaddr_desc *xioaddrs_tcp6_listen[] = { (union xioaddr_desc *)&xioendpoint_tcp6_listen1, NULL };
#endif #endif
#endif /* WITH_IP6 */ #endif /* WITH_IP6 */

View file

@ -1,16 +1,16 @@
/* $Id: xio-tcp.h,v 1.12 2006/03/21 20:59:34 gerhard Exp $ */ /* $Id: xio-tcp.h,v 1.12.2.1 2006/07/24 19:18:42 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_tcp_h_included #ifndef __xio_tcp_h_included
#define __xio_tcp_h_included 1 #define __xio_tcp_h_included 1
extern const struct addrdesc addr_tcp_connect; extern const union xioaddr_desc *xioaddrs_tcp_connect[];
extern const struct addrdesc addr_tcp_listen; extern const union xioaddr_desc *xioaddrs_tcp_listen[];
extern const struct addrdesc addr_tcp4_connect; extern const union xioaddr_desc *xioaddrs_tcp4_connect[];
extern const struct addrdesc addr_tcp4_listen; extern const union xioaddr_desc *xioaddrs_tcp4_listen[];
extern const struct addrdesc addr_tcp6_connect; extern const union xioaddr_desc *xioaddrs_tcp6_connect[];
extern const struct addrdesc addr_tcp6_listen; extern const union xioaddr_desc *xioaddrs_tcp6_listen[];
extern const struct optdesc opt_tcp_nodelay; extern const struct optdesc opt_tcp_nodelay;
extern const struct optdesc opt_tcp_maxseg; extern const struct optdesc opt_tcp_maxseg;

View file

@ -131,11 +131,11 @@ int xio_tcpwrap_check(xiosingle_t *xfd, union sockaddr_union *us,
Warn1("inet_ntop(): %s", strerror(errno)); Warn1("inet_ntop(): %s", strerror(errno));
} }
Debug7("request_init(%p, RQ_FILE, %d, RQ_CLIENT_SIN, {%s:%u}, RQ_SERVER_SIN, {%s:%u}, RQ_DAEMON, \"%s\", 0", Debug7("request_init(%p, RQ_FILE, %d, RQ_CLIENT_SIN, {%s:%u}, RQ_SERVER_SIN, {%s:%u}, RQ_DAEMON, \"%s\", 0",
&ri, xfd->fd, clientaddr, &ri, xfd->fd1, clientaddr,
ntohs(((struct sockaddr_in *)them)->sin_port), ntohs(((struct sockaddr_in *)them)->sin_port),
serveraddr, ntohs(us->ip4.sin_port), serveraddr, ntohs(us->ip4.sin_port),
xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p')); xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p'));
request_init(&ri, RQ_FILE, xfd->fd, request_init(&ri, RQ_FILE, xfd->fd1,
RQ_CLIENT_SIN, them, RQ_CLIENT_SIN, them,
RQ_SERVER_SIN, &us->soa, RQ_SERVER_SIN, &us->soa,
RQ_DAEMON, xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p'), 0); RQ_DAEMON, xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p'), 0);

228
xio-test.c Normal file
View file

@ -0,0 +1,228 @@
/* $Id$ */
/* Copyright Gerhard Rieger 2007 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for an intermediate test address that appends
'>' to every block transferred from right to left, and '<' in the other
direction */
#include "xiosysincludes.h"
#include "xioopen.h"
#include "xio-test.h"
#if WITH_TEST
static int xioopen_test(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd,
unsigned groups, int dummy1, int dummy2,
int dummy3);
static int xioopen_testuni(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd,
unsigned groups, int dummy1, int dummy2,
int dummy3);
static int xioopen_testrev(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd,
unsigned groups, int dummy1, int dummy2,
int dummy3);
static const struct xioaddr_inter_desc xiointer_test0ro = { XIOADDR_PROT, "test", 0, XIOBIT_RDONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_test, 0, 0, 0, XIOBIT_WRONLY HELP("") };
static const struct xioaddr_inter_desc xiointer_test0wo = { XIOADDR_PROT, "test", 0, XIOBIT_WRONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_test, 0, 0, 0, XIOBIT_RDONLY HELP("") };
static const struct xioaddr_inter_desc xiointer_test0rw = { XIOADDR_PROT, "test", 0, XIOBIT_RDWR, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_test, 0, 0, 0, XIOBIT_RDWR HELP("") };
const union xioaddr_desc *xioaddrs_test[] = {
(union xioaddr_desc *)&xiointer_test0ro,
(union xioaddr_desc *)&xiointer_test0wo,
(union xioaddr_desc *)&xiointer_test0rw,
NULL };
static const struct xioaddr_inter_desc xiointer_testuni = { XIOADDR_PROT, "testuni", 0, XIOBIT_WRONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_testuni, 0, 0, 0, XIOBIT_RDONLY HELP("") };
const union xioaddr_desc *xioaddrs_testuni[] = {
(union xioaddr_desc *)&xiointer_testuni,
NULL };
static const struct xioaddr_inter_desc xiointer_testrev = { XIOADDR_PROT, "testrev", 0, XIOBIT_WRONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_testrev, 0, 0, 0, XIOBIT_RDONLY HELP("") };
const union xioaddr_desc *xioaddrs_testrev[] = {
(union xioaddr_desc *)&xiointer_testrev,
NULL };
static int xioopen_test(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd,
unsigned groups, int dummy, int dummy2,
int dummy3) {
struct single *xfd = &xxfd->stream;
int result;
assert(argc == 1);
assert(!(xfd->fd1 < 0 && xfd->fd2 < 0));
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
Notice("opening TEST");
xfd->dtype = XIODATA_TEST;
applyopts(xfd->fd1, opts, PH_ALL);
if ((result = _xio_openlate(xfd, opts)) < 0)
return result;
return 0;
}
static int xioopen_testuni(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd,
unsigned groups, int dummy, int dummy2,
int dummy3) {
struct single *xfd = &xxfd->stream;
int result;
assert(argc == 1);
assert(!(xfd->fd1 < 0 && xfd->fd2 < 0));
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
Notice("opening TESTUNI");
xfd->dtype = XIODATA_TESTUNI;
applyopts(xfd->fd1, opts, PH_ALL);
if ((result = _xio_openlate(xfd, opts)) < 0)
return result;
return 0;
}
static int xioopen_testrev(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd,
unsigned groups, int dummy, int dummy2,
int dummy3) {
struct single *xfd = &xxfd->stream;
int result;
assert(argc == 1);
assert(!(xfd->fd1 < 0 && xfd->fd2 < 0));
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
Notice("opening TESTREV");
xfd->dtype = XIODATA_TESTREV;
applyopts(xfd->fd1, opts, PH_ALL);
if ((result = _xio_openlate(xfd, opts)) < 0)
return result;
return 0;
}
size_t xioread_test(struct single *sfd, void *buff, size_t bufsiz) {
int fd = sfd->fd1;
ssize_t bytes;
int _errno;
do {
bytes = Read(fd, buff, bufsiz-1);
} while (bytes < 0 && errno == EINTR);
if (bytes < 0) {
_errno = errno;
switch (_errno) {
case EPIPE: case ECONNRESET:
Warn4("read(%d, %p, "F_Zu"): %s",
fd, buff, bufsiz-1, strerror(_errno));
break;
default:
Error4("read(%d, %p, "F_Zu"): %s",
fd, buff, bufsiz-1, strerror(_errno));
}
return -1;
}
if (bytes == 0) {
return 0;
}
((char *)buff)[bytes] = '<';
return bytes+1;
}
size_t xiowrite_test(struct single *sfd, const void *buff, size_t bytes) {
int fd = ((sfd->fdtype==FDTYPE_DOUBLE)?sfd->fd2:sfd->fd1);
void *buff1;
ssize_t writt;
int _errno;
if ((buff1 = Malloc(bytes+1)) == NULL) {
return -1;
}
memcpy(buff1, buff, bytes);
((char *)buff1)[bytes] = '>';
do {
writt = Write(fd, buff1, bytes+1);
} while (writt < 0 && errno == EINTR);
if (writt < 0) {
_errno = errno;
switch (_errno) {
case EPIPE:
case ECONNRESET:
if (sfd->cool_write) {
Notice4("write(%d, %p, "F_Zu"): %s",
fd, buff1, bytes+1, strerror(_errno));
break;
}
/*PASSTHROUGH*/
default:
Error4("write(%d, %p, "F_Zu"): %s",
fd, buff1, bytes+1, strerror(_errno));
}
errno = _errno;
free(buff1);
return -1;
}
if ((size_t)writt < bytes) {
Warn2("write() only wrote "F_Zu" of "F_Zu" bytes",
writt, bytes+1);
}
free(buff1);
return writt;
}
size_t xiowrite_testrev(struct single *sfd, const void *buff, size_t bytes) {
int fd = ((sfd->fdtype==FDTYPE_DOUBLE)?sfd->fd2:sfd->fd1);
void *buff1;
ssize_t writt;
int _errno;
if ((buff1 = Malloc(bytes+1)) == NULL) {
return -1;
}
memcpy(buff1, buff, bytes);
((char *)buff1)[bytes] = '<';
do {
writt = Write(fd, buff1, bytes+1);
} while (writt < 0 && errno == EINTR);
if (writt < 0) {
_errno = errno;
switch (_errno) {
case EPIPE:
case ECONNRESET:
if (sfd->cool_write) {
Notice4("write(%d, %p, "F_Zu"): %s",
fd, buff1, bytes+1, strerror(_errno));
break;
}
/*PASSTHROUGH*/
default:
Error4("write(%d, %p, "F_Zu"): %s",
fd, buff1, bytes+1, strerror(_errno));
}
errno = _errno;
free(buff1);
return -1;
}
if ((size_t)writt < bytes) {
Warn2("write() only wrote "F_Zu" of "F_Zu" bytes",
writt, bytes+1);
}
free(buff1);
return writt;
}
#endif /* WITH_TEST */

16
xio-test.h Normal file
View file

@ -0,0 +1,16 @@
/* $Id$ */
/* Copyright Gerhard Rieger 2007 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_test_h_included
#define __xio_test_h_included 1
extern const union xioaddr_desc *xioaddrs_test[];
extern const union xioaddr_desc *xioaddrs_testuni[];
extern const union xioaddr_desc *xioaddrs_testrev[];
extern size_t xioread_test(struct single *sfd, void *buff, size_t bufsiz);
extern size_t xiowrite_test(struct single *sfd, const void *buff, size_t bytes);
extern size_t xiowrite_testrev(struct single *sfd, const void *buff, size_t bytes);
#endif /* !defined(__xio_test_h_included) */

View file

@ -46,7 +46,13 @@ const struct optdesc opt_iff_automedia = { "iff-automedia", "automedia", O
const struct optdesc opt_route = { "route", NULL, OPT_ROUTE, GROUP_INTERFACE, PH_INIT, TYPE_STRING, OFUNC_SPEC }; const struct optdesc opt_route = { "route", NULL, OPT_ROUTE, GROUP_INTERFACE, PH_INIT, TYPE_STRING, OFUNC_SPEC };
#endif #endif
const struct addrdesc xioaddr_tun = { "tun", 3, xioopen_tun, GROUP_FD|GROUP_CHR|GROUP_NAMED|GROUP_OPEN|GROUP_TUN, 0, 0, 0 HELP(":<ip-addr>/<bits>") }; static const struct xioaddr_endpoint_desc xioendpoint_tun1 = { XIOADDR_SYS, "tun", 1, XIOBIT_ALL, GROUP_FD|GROUP_CHR|GROUP_NAMED|GROUP_OPEN|GROUP_TUN, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_tun, 0, 0, 0 HELP(":<ip-addr>/<bits>") };
const union xioaddr_desc *xioaddrs_tun[] = {
(union xioaddr_desc *)&xioendpoint_tun1,
NULL
};
// "if-name"=tun3 // "if-name"=tun3
// "route"=address/netmask // "route"=address/netmask
// "ip6-route"=address/netmask // "ip6-route"=address/netmask
@ -101,7 +107,7 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
Notice("creating tunnel network interface"); Notice("creating tunnel network interface");
if ((result = _xioopen_open(tundevice, rw, opts)) < 0) if ((result = _xioopen_open(tundevice, rw, opts)) < 0)
return result; return result;
xfd->stream.fd = result; xfd->stream.fd1 = result;
/* prepare configuration of the new network interface */ /* prepare configuration of the new network interface */
memset(&ifr, 0,sizeof(ifr)); memset(&ifr, 0,sizeof(ifr));
@ -132,10 +138,10 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
} }
} }
if (Ioctl(xfd->stream.fd, TUNSETIFF, &ifr) < 0) { if (Ioctl(xfd->stream.fd1, TUNSETIFF, &ifr) < 0) {
Error3("ioctl(%d, TUNSETIFF, {\"%s\"}: %s", Error3("ioctl(%d, TUNSETIFF, {\"%s\"}: %s",
xfd->stream.fd, ifr.ifr_name, strerror(errno)); xfd->stream.fd1, ifr.ifr_name, strerror(errno));
Close(xfd->stream.fd); Close(xfd->stream.fd1);
} }
/*===================== setting interface properties =====================*/ /*===================== setting interface properties =====================*/
@ -143,7 +149,7 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
/* we seem to need a socket for manipulating the interface */ /* we seem to need a socket for manipulating the interface */
if ((sockfd = Socket(PF_INET, SOCK_DGRAM, 0)) < 0) { if ((sockfd = Socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
Error1("socket(PF_INET, SOCK_DGRAM, 0): %s", strerror(errno)); Error1("socket(PF_INET, SOCK_DGRAM, 0): %s", strerror(errno));
sockfd = xfd->stream.fd; /* desparate fallback attempt */ sockfd = xfd->stream.fd1; /* desparate fallback attempt */
} }
/*--------------------- setting interface address and netmask ------------*/ /*--------------------- setting interface address and netmask ------------*/
@ -195,10 +201,10 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
#if LATER #if LATER
applyopts_named(tundevice, opts, PH_FD); applyopts_named(tundevice, opts, PH_FD);
#endif #endif
applyopts(xfd->stream.fd, opts, PH_FD); applyopts(xfd->stream.fd1, opts, PH_FD);
applyopts_cloexec(xfd->stream.fd, opts); applyopts_cloexec(xfd->stream.fd1, opts);
applyopts_fchown(xfd->stream.fd, opts); applyopts_fchown(xfd->stream.fd1, opts);
if ((result = _xio_openlate(&xfd->stream, opts)) < 0) if ((result = _xio_openlate(&xfd->stream, opts)) < 0)
return result; return result;

View file

@ -28,6 +28,6 @@ extern const struct optdesc opt_iff_portsel;
extern const struct optdesc opt_iff_automedia; extern const struct optdesc opt_iff_automedia;
/*extern const struct optdesc opt_iff_dynamic;*/ /*extern const struct optdesc opt_iff_dynamic;*/
extern const struct addrdesc xioaddr_tun; extern const union xioaddr_desc *xioaddrs_tun[];
#endif /* !defined(__xio_tun_h_included) */ #endif /* !defined(__xio_tun_h_included) */

110
xio-udp.c
View file

@ -35,42 +35,59 @@ static
int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts, int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups, int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int socktype, int ipproto); int pf, int socktype, int ipproto);
static static
int _xioopen_udp_sendto(const char *hostname, const char *servname, int _xioopen_udp_sendto(const char *hostname, const char *servname,
struct opt *opts, struct opt *opts,
int xioflags, xiofile_t *xxfd, unsigned groups, int xioflags, xiofile_t *xxfd, unsigned groups,
int pf, int socktype, int ipproto); int pf, int socktype, int ipproto);
const struct addrdesc addr_udp_connect = { "udp-connect", 3, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP, SOCK_DGRAM, IPPROTO_UDP, PF_UNSPEC HELP(":<host>:<port>") }; static const struct xioaddr_endpoint_desc xioaddr_udp_connect2 = { XIOADDR_SYS, "udp-connect", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_connect, SOCK_DGRAM, IPPROTO_UDP, PF_UNSPEC HELP(":<host>:<port>") };
const union xioaddr_desc *xioaddrs_udp_connect[] = { (union xioaddr_desc *)&xioaddr_udp_connect2, NULL };
#if WITH_LISTEN #if WITH_LISTEN
const struct addrdesc addr_udp_listen = { "udp-listen", 3, xioopen_ipdgram_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, PF_UNSPEC, IPPROTO_UDP, PF_UNSPEC HELP(":<port>") }; static const struct xioaddr_endpoint_desc xioaddr_udp_listen1 = { XIOADDR_SYS, "udp-listen", 1, XIOBIT_RDONLY|XIO_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipdgram_listen, PF_UNSPEC, IPPROTO_UDP, PF_UNSPEC HELP(":<port>") };
const union xioaddr_desc *xioaddrs_udp_listen[] = { (union xioaddr_desc *)&xioaddr_udp_listen1, NULL };
#endif /* WITH_LISTEN */ #endif /* WITH_LISTEN */
const struct addrdesc addr_udp_sendto = { "udp-sendto", 3, xioopen_udp_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") }; static const struct xioaddr_endpoint_desc xioaddr_udp_sendto2 = { XIOADDR_SYS, "udp-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_sendto, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
const struct addrdesc addr_udp_recvfrom = { "udp-recvfrom", 3, xioopen_udp_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") }; const union xioaddr_desc *xioaddrs_udp_sendto[] = { (union xioaddr_desc *)&xioaddr_udp_sendto2, NULL };
const struct addrdesc addr_udp_recv = { "udp-recv", 1, xioopen_udp_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") }; static const struct xioaddr_endpoint_desc xioaddr_udp_recvfrom1 = { XIOADDR_SYS, "udp-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_udp_recvfrom, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
const struct addrdesc addr_udp_datagram = { "udp-datagram", 3, xioopen_udp_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") }; const union xioaddr_desc *xioaddrs_udp_recvfrom[] = { (union xioaddr_desc *)&xioaddr_udp_recvfrom1, NULL };
static const struct xioaddr_endpoint_desc xioaddr_udp_recv1 = { XIOADDR_SYS, "udp-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_recv, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
const union xioaddr_desc *xioaddrs_udp_recv[] = { (union xioaddr_desc *)&xioaddr_udp_recv1, NULL };
static const struct xioaddr_endpoint_desc xioaddr_udp_datagram2 = { XIOADDR_SYS, "udp-datagram", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_datagram, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
const union xioaddr_desc *xioaddrs_udp_datagram[] = { (union xioaddr_desc *)&xioaddr_udp_datagram2, NULL };
#if WITH_IP4 #if WITH_IP4
const struct addrdesc addr_udp4_connect = { "udp4-connect", 3, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP, SOCK_DGRAM, IPPROTO_UDP, PF_INET HELP(":<host>:<port>") }; static const struct xioaddr_endpoint_desc xioaddr_udp4_connect2 = { XIOADDR_SYS, "udp4-connect", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_connect, SOCK_DGRAM, IPPROTO_UDP, PF_INET HELP(":<host>:<port>") };
const union xioaddr_desc *xioaddrs_udp4_connect[] = { (union xioaddr_desc *)&xioaddr_udp4_connect2, NULL };
#if WITH_LISTEN #if WITH_LISTEN
const struct addrdesc addr_udp4_listen = { "udp4-listen", 3, xioopen_ipdgram_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, PF_INET, IPPROTO_UDP, PF_INET HELP(":<port>") }; static const struct xioaddr_endpoint_desc xioaddr_udp4_listen1 = { XIOADDR_SYS, "udp4-listen", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipdgram_listen, PF_INET, IPPROTO_UDP, PF_INET HELP(":<port>") };
const union xioaddr_desc *xioaddrs_udp4_listen[] = { (union xioaddr_desc *)&xioaddr_udp4_listen1, NULL };
#endif /* WITH_LISTEN */ #endif /* WITH_LISTEN */
const struct addrdesc addr_udp4_sendto = { "udp4-sendto", 3, xioopen_udp_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") }; static const struct xioaddr_endpoint_desc xioaddr_udp4_sendto2 = { XIOADDR_SYS, "udp4-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_sendto, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
const struct addrdesc addr_udp4_datagram = { "udp4-datagram",3, xioopen_udp_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_RANGE, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<remote-address>:<port>") }; const union xioaddr_desc *xioaddrs_udp4_sendto[] = { (union xioaddr_desc *)&xioaddr_udp4_sendto2, NULL };
const struct addrdesc addr_udp4_recvfrom= { "udp4-recvfrom", 3, xioopen_udp_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") }; static const struct xioaddr_endpoint_desc xioaddr_udp4_datagram2= { XIOADDR_SYS, "udp4-datagram",2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_datagram, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
const struct addrdesc addr_udp4_recv = { "udp4-recv", 1, xioopen_udp_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_RANGE, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") }; const union xioaddr_desc *xioaddrs_udp4_datagram[] = { (union xioaddr_desc *)&xioaddr_udp4_datagram2, NULL };
static const struct xioaddr_endpoint_desc xioaddr_udp4_recvfrom1= { XIOADDR_SYS, "udp4-recvfrom",1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_udp_recvfrom, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
const union xioaddr_desc *xioaddrs_udp4_recvfrom[] = { (union xioaddr_desc *)&xioaddr_udp4_recvfrom1, NULL };
static const struct xioaddr_endpoint_desc xioaddr_udp4_recv1 = { XIOADDR_SYS, "udp4-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_recv, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
const union xioaddr_desc *xioaddrs_udp4_recv[] = { (union xioaddr_desc *)&xioaddr_udp4_recv1, NULL };
#endif /* WITH_IP4 */ #endif /* WITH_IP4 */
#if WITH_IP6 #if WITH_IP6
const struct addrdesc addr_udp6_connect = { "udp6-connect", 3, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP, SOCK_DGRAM, IPPROTO_UDP, PF_INET6 HELP(":<host>:<port>") }; static const struct xioaddr_endpoint_desc xioaddr_udp6_connect2 = { XIOADDR_SYS, "udp6-connect", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_connect, SOCK_DGRAM, IPPROTO_UDP, PF_INET6 HELP(":<host>:<port>") };
const union xioaddr_desc *xioaddrs_udp6_connect[] = { (union xioaddr_desc *)&xioaddr_udp6_connect2, NULL };
#if WITH_LISTEN #if WITH_LISTEN
const struct addrdesc addr_udp6_listen = { "udp6-listen", 3, xioopen_ipdgram_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, PF_INET6, IPPROTO_UDP, 0 HELP(":<port>") }; static const struct xioaddr_endpoint_desc xioaddr_udp6_listen1 = { XIOADDR_SYS, "udp6-listen", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipdgram_listen, PF_INET6, IPPROTO_UDP, 0 HELP(":<port>") };
const union xioaddr_desc *xioaddrs_udp6_listen[] = { (union xioaddr_desc *)&xioaddr_udp6_listen1, NULL };
#endif /* WITH_LISTEN */ #endif /* WITH_LISTEN */
const struct addrdesc addr_udp6_sendto = { "udp6-sendto", 3, xioopen_udp_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") }; static const struct xioaddr_endpoint_desc xioaddr_udp6_sendto2 = { XIOADDR_SYS, "udp6-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_sendto, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
const struct addrdesc addr_udp6_datagram= { "udp6-datagram", 3, xioopen_udp_datagram,GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") }; const union xioaddr_desc *xioaddrs_udp6_sendto[] = { (union xioaddr_desc *)&xioaddr_udp6_sendto2, NULL };
const struct addrdesc addr_udp6_recvfrom= { "udp6-recvfrom", 3, xioopen_udp_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") }; static const struct xioaddr_endpoint_desc xioaddr_udp6_datagram2= { XIOADDR_SYS, "udp6-datagram",2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_datagram, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
const struct addrdesc addr_udp6_recv = { "udp6-recv", 1, xioopen_udp_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") }; const union xioaddr_desc *xioaddrs_udp6_datagram[] = { (union xioaddr_desc *)&xioaddr_udp6_datagram2, NULL };
static const struct xioaddr_endpoint_desc xioaddr_udp6_recvfrom1= { XIOADDR_SYS, "udp6-recvfrom",1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_udp_recvfrom, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
const union xioaddr_desc *xioaddrs_udp6_recvfrom[] = { (union xioaddr_desc *)&xioaddr_udp6_recvfrom1, NULL };
static const struct xioaddr_endpoint_desc xioaddr_udp6_recv1 = { XIOADDR_SYS, "udp6-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_recv, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
const union xioaddr_desc *xioaddrs_udp6_recv[] = { (union xioaddr_desc *)&xioaddr_udp6_recv1, NULL };
#endif /* WITH_IP6 */ #endif /* WITH_IP6 */
@ -113,6 +130,8 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1; if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
fd->stream.fdtype = FDTYPE_SINGLE;
uslen = socket_init(pf, &us); uslen = socket_init(pf, &us);
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bind(opts, pf, socktype, IPPROTO_UDP, retropt_bind(opts, pf, socktype, IPPROTO_UDP,
@ -172,61 +191,61 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
union sockaddr_union _sockname; union sockaddr_union _sockname;
union sockaddr_union *la = &_sockname; /* local address */ union sockaddr_union *la = &_sockname; /* local address */
if ((fd->stream.fd = Socket(pf, socktype, ipproto)) < 0) { if ((fd->stream.fd1 = Socket(pf, socktype, ipproto)) < 0) {
Error4("socket(%d, %d, %d): %s", pf, socktype, ipproto, strerror(errno)); Error4("socket(%d, %d, %d): %s", pf, socktype, ipproto, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
applyopts(fd->stream.fd, opts, PH_PASTSOCKET); /*0 Info4("socket(%d, %d, %d) -> %d", pf, socktype, ipproto, fd->stream.fd);*/
if (Setsockopt(fd->stream.fd, opt_so_reuseaddr.major, applyopts(fd->stream.fd1, opts, PH_PASTSOCKET);
if (Setsockopt(fd->stream.fd1, opt_so_reuseaddr.major,
opt_so_reuseaddr.minor, &one, sizeof(one)) < 0) { opt_so_reuseaddr.minor, &one, sizeof(one)) < 0) {
Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd"): %s", Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd"): %s",
fd->stream.fd, opt_so_reuseaddr.major, fd->stream.fd1, opt_so_reuseaddr.major,
opt_so_reuseaddr.minor, one, sizeof(one), strerror(errno)); opt_so_reuseaddr.minor, one, sizeof(one), strerror(errno));
} }
applyopts_cloexec(fd->stream.fd, opts); applyopts_cloexec(fd->stream.fd1, opts);
applyopts(fd->stream.fd, opts, PH_PREBIND); applyopts(fd->stream.fd1, opts, PH_PREBIND);
applyopts(fd->stream.fd, opts, PH_BIND); applyopts(fd->stream.fd1, opts, PH_BIND);
if (Bind(fd->stream.fd, &us.soa, uslen) < 0) { if (Bind(fd->stream.fd1, &us.soa, uslen) < 0) {
Error4("bind(%d, {%s}, "F_Zd"): %s", fd->stream.fd, Error4("bind(%d, {%s}, "F_Zd"): %s", fd->stream.fd1,
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)), sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)),
uslen, strerror(errno)); uslen, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
/* under some circumstances bind() fills sockaddr with interesting info. */ /* under some circumstances bind() fills sockaddr with interesting info. */
if (Getsockname(fd->stream.fd, &us.soa, &uslen) < 0) { if (Getsockname(fd->stream.fd1, &us.soa, &uslen) < 0) {
Error4("getsockname(%d, %p, {%d}): %s", Error4("getsockname(%d, %p, {%d}): %s",
fd->stream.fd, &us.soa, uslen, strerror(errno)); fd->stream.fd1, &us.soa, uslen, strerror(errno));
} }
applyopts(fd->stream.fd, opts, PH_PASTBIND); applyopts(fd->stream.fd1, opts, PH_PASTBIND);
Notice1("listening on UDP %s", Notice1("listening on UDP %s",
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff))); sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)));
FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt); FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt);
FD_SET(fd->stream.fd, &in); FD_SET(fd->stream.fd1, &in);
while (Select(fd->stream.fd+1, &in, &out, &expt, NULL) < 0) { while (Select(fd->stream.fd1+1, &in, &out, &expt, NULL) < 0) {
if (errno != EINTR) break; if (errno != EINTR) break;
} }
themlen = socket_init(pf, them); themlen = socket_init(pf, them);
do { do {
result = Recvfrom(fd->stream.fd, buff1, 1, MSG_PEEK, result = Recvfrom(fd->stream.fd1, buff1, 1, MSG_PEEK,
&them->soa, &themlen); &them->soa, &themlen);
} while (result < 0 && errno == EINTR); } while (result < 0 && errno == EINTR);
if (result < 0) { if (result < 0) {
Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_Zu"}): %s", Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_Zu"}): %s",
fd->stream.fd, buff1, fd->stream.fd1, buff1,
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)), sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
Notice1("accepting UDP connection from %s", Notice1("accepting UDP connection from %s",
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff))); sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)));
if (xiocheckpeer(&fd->stream, them, la) < 0) { if (xiocheckpeer(&fd->stream, them, la) < 0) {
/* drop packet */ /* drop packet */
char buff[512]; char buff[512];
Recv(fd->stream.fd, buff, sizeof(buff), 0); Recv(fd->stream.fd1, buff, sizeof(buff), 0);
continue; continue;
} }
Info1("permitting UDP connection from %s", Info1("permitting UDP connection from %s",
@ -249,8 +268,8 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
/* server: continue loop with select */ /* server: continue loop with select */
/* when we dont close this we get awkward behaviour on Linux 2.4: /* when we dont close this we get awkward behaviour on Linux 2.4:
recvfrom gives 0 bytes with invalid socket address */ recvfrom gives 0 bytes with invalid socket address */
if (Close(fd->stream.fd) < 0) { if (Close(fd->stream.fd1) < 0) {
Info2("close(%d): %s", fd->stream.fd, strerror(errno)); Info2("close(%d): %s", fd->stream.fd1, strerror(errno));
} }
Notice1("forked off child process "F_pid, pid); Notice1("forked off child process "F_pid, pid);
Sleep(1); /*! give child a chance to consume the old packet */ Sleep(1); /*! give child a chance to consume the old packet */
@ -260,18 +279,17 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
break; break;
} }
applyopts(fd->stream.fd, opts, PH_CONNECT); applyopts(fd->stream.fd1, opts, PH_CONNECT);
if ((result = Connect(fd->stream.fd, &them->soa, themlen)) < 0) { if ((result = Connect(fd->stream.fd1, &them->soa, themlen)) < 0) {
Error4("connect(%d, {%s}, "F_Zd"): %s", Error4("connect(%d, {%s}, "F_Zd"): %s",
fd->stream.fd, fd->stream.fd1,
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)), sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
fd->stream.howtoend = END_SHUTDOWN; applyopts_fchown(fd->stream.fd1, opts);
applyopts_fchown(fd->stream.fd, opts); applyopts(fd->stream.fd1, opts, PH_LATE);
applyopts(fd->stream.fd, opts, PH_LATE);
if ((result = _xio_openlate(&fd->stream, opts)) < 0) if ((result = _xio_openlate(&fd->stream, opts)) < 0)
return result; return result;
@ -312,7 +330,6 @@ int _xioopen_udp_sendto(const char *hostname, const char *servname,
bool needbind = false; bool needbind = false;
int result; int result;
xfd->howtoend = END_SHUTDOWN;
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
/* ...res_opts[] */ /* ...res_opts[] */
@ -452,7 +469,6 @@ int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts,
return STAT_NORETRY; return STAT_NORETRY;
} }
xfd->stream.howtoend = END_NONE;
retropt_socket_pf(opts, &pf); retropt_socket_pf(opts, &pf);
if (pf == PF_UNSPEC) { if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6 #if WITH_IP4 && WITH_IP6

View file

@ -5,24 +5,24 @@
#ifndef __xio_udp_h_included #ifndef __xio_udp_h_included
#define __xio_udp_h_included 1 #define __xio_udp_h_included 1
extern const struct addrdesc addr_udp_connect; extern const union xioaddr_desc *xioaddrs_udp_connect[];
extern const struct addrdesc addr_udp_listen; extern const union xioaddr_desc *xioaddrs_udp_listen[];
extern const struct addrdesc addr_udp_sendto; extern const union xioaddr_desc *xioaddrs_udp_sendto[];
extern const struct addrdesc addr_udp_datagram; extern const union xioaddr_desc *xioaddrs_udp_datagram[];
extern const struct addrdesc addr_udp_recvfrom; extern const union xioaddr_desc *xioaddrs_udp_recvfrom[];
extern const struct addrdesc addr_udp_recv; extern const union xioaddr_desc *xioaddrs_udp_recv[];
extern const struct addrdesc addr_udp4_connect; extern const union xioaddr_desc *xioaddrs_udp4_connect[];
extern const struct addrdesc addr_udp4_listen; extern const union xioaddr_desc *xioaddrs_udp4_listen[];
extern const struct addrdesc addr_udp4_sendto; extern const union xioaddr_desc *xioaddrs_udp4_sendto[];
extern const struct addrdesc addr_udp4_datagram; extern const union xioaddr_desc *xioaddrs_udp4_datagram[];
extern const struct addrdesc addr_udp4_recvfrom; extern const union xioaddr_desc *xioaddrs_udp4_recvfrom[];
extern const struct addrdesc addr_udp4_recv; extern const union xioaddr_desc *xioaddrs_udp4_recv[];
extern const struct addrdesc addr_udp6_connect; extern const union xioaddr_desc *xioaddrs_udp6_connect[];
extern const struct addrdesc addr_udp6_listen; extern const union xioaddr_desc *xioaddrs_udp6_listen[];
extern const struct addrdesc addr_udp6_sendto; extern const union xioaddr_desc *xioaddrs_udp6_sendto[];
extern const struct addrdesc addr_udp6_datagram; extern const union xioaddr_desc *xioaddrs_udp6_datagram[];
extern const struct addrdesc addr_udp6_recvfrom; extern const union xioaddr_desc *xioaddrs_udp6_recvfrom[];
extern const struct addrdesc addr_udp6_recv; extern const union xioaddr_desc *xioaddrs_udp6_recv[];
extern int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, extern int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
int rw, xiofile_t *fd, int rw, xiofile_t *fd,

View file

@ -25,7 +25,6 @@ int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts,
int pf, int socktype, int ipproto); int pf, int socktype, int ipproto);
static static
int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3); int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3);
#if WITH_ABSTRACT_UNIXSOCKET #if WITH_ABSTRACT_UNIXSOCKET
static int xioopen_abstract_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); static int xioopen_abstract_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
static int xioopen_abstract_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); static int xioopen_abstract_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
@ -39,23 +38,36 @@ static
int xioopen_abstract_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3); int xioopen_abstract_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3);
#endif /* WITH_ABSTRACT_UNIXSOCKET */ #endif /* WITH_ABSTRACT_UNIXSOCKET */
const struct addrdesc addr_unix_connect = { "unix-connect", 3, xioopen_unix_connect, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") }; static const struct xioaddr_endpoint_desc xioendpoint_unix_connect1 = { XIOADDR_SYS, "unix-connect", 1, XIOBIT_ALL, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_connect, 0, SOCK_STREAM, 0 HELP(":<filename>") };
const union xioaddr_desc *xioaddrs_unix_connect[] = { (union xioaddr_desc *)&xioendpoint_unix_connect1, NULL };
#if WITH_LISTEN #if WITH_LISTEN
const struct addrdesc addr_unix_listen = { "unix-listen", 3, xioopen_unix_listen, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") }; static const struct xioaddr_endpoint_desc xioendpoint_unix_listen1 = { XIOADDR_SYS, "unix-listen", 1, XIOBIT_ALL, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_listen, 0, SOCK_STREAM, 0 HELP(":<filename>") };
const union xioaddr_desc *xioaddrs_unix_listen[] = { (union xioaddr_desc *)&xioendpoint_unix_listen1, NULL };
#endif /* WITH_LISTEN */ #endif /* WITH_LISTEN */
const struct addrdesc addr_unix_sendto = { "unix-sendto", 3, xioopen_unix_sendto, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_DGRAM, 0 HELP(":<filename>") }; static const struct xioaddr_endpoint_desc xioendpoint_unix_sendto1 = { XIOADDR_SYS, "unix-sendto", 1, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_sendto, 0, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc addr_unix_recvfrom= { "unix-recvfrom", 3, xioopen_unix_recvfrom, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") }; const union xioaddr_desc *xioaddrs_unix_sendto[] = { (union xioaddr_desc *)&xioendpoint_unix_sendto1, NULL };
const struct addrdesc addr_unix_recv = { "unix-recv", 1, xioopen_unix_recv, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") }; static const struct xioaddr_endpoint_desc xioendpoint_unix_recvfrom1= { XIOADDR_SYS, "unix-recvfrom",1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_unix_recvfrom, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc addr_unix_client = { "unix-client", 3, xioopen_unix_client, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, 0, 0 HELP(":<filename>") }; const union xioaddr_desc *xioaddrs_unix_recvfrom[]= { (union xioaddr_desc *)&xioendpoint_unix_recvfrom1, NULL };
static const struct xioaddr_endpoint_desc xioendpoint_unix_recv1 = { XIOADDR_SYS, "unix-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_unix_recv, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
const union xioaddr_desc *xioaddrs_unix_recv[] = { (union xioaddr_desc *)&xioendpoint_unix_recv1, NULL };
static const struct xioaddr_endpoint_desc xioendpoint_unix_client1 = { XIOADDR_SYS, "unix-client", 1, XIOBIT_ALL, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_client, PF_UNIX, 0, 0 HELP(":<filename>") };
const union xioaddr_desc *xioaddrs_unix_client[] = { (union xioaddr_desc *)&xioendpoint_unix_client1, NULL };
#if WITH_ABSTRACT_UNIXSOCKET #if WITH_ABSTRACT_UNIXSOCKET
const struct addrdesc xioaddr_abstract_connect = { "abstract-connect", 3, xioopen_abstract_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") }; static const struct xioaddr_endpoint_desc xioendpoint_abstract_connect1 = { XIOADDR_SYS, "abstract-connect", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_abstract_connect, 0, SOCK_STREAM, 0 HELP(":<filename>") };
const union xioaddr_desc *xioaddrs_abstract_connect[] = { (union xioaddr_desc *)&xioendpoint_abstract_connect1, NULL };
#if WITH_LISTEN #if WITH_LISTEN
const struct addrdesc xioaddr_abstract_listen = { "abstract-listen", 3, xioopen_abstract_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") }; static const struct xioaddr_endpoint_desc xioendpoint_abstract_listen1 = { XIOADDR_SYS, "abstract-listen", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_abstract_listen, 0, SOCK_STREAM, 0 HELP(":<filename>") };
const union xioaddr_desc *xioaddrs_abstract_listen[] = { (union xioaddr_desc *)&xioendpoint_abstract_listen1, NULL };
#endif /* WITH_LISTEN */ #endif /* WITH_LISTEN */
const struct addrdesc xioaddr_abstract_sendto = { "abstract-sendto", 3, xioopen_abstract_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_DGRAM, 0 HELP(":<filename>") }; static const struct xioaddr_endpoint_desc xioendpoint_abstract_sendto1 = { XIOADDR_SYS, "abstract-sendto", 1, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_abstract_sendto, 0, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc xioaddr_abstract_recvfrom= { "abstract-recvfrom", 3, xioopen_abstract_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") }; const union xioaddr_desc *xioaddrs_abstract_sendto[] = { (union xioaddr_desc *)&xioendpoint_abstract_sendto1, NULL };
const struct addrdesc xioaddr_abstract_recv = { "abstract-recv", 1, xioopen_abstract_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") }; static const struct xioaddr_endpoint_desc xioendpoint_abstract_recvfrom1= { XIOADDR_SYS, "abstract-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_abstract_recvfrom, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc xioaddr_abstract_client = { "abstract-client", 3, xioopen_abstract_client, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, 0, 0 HELP(":<filename>") }; const union xioaddr_desc *xioaddrs_abstract_recvfrom[] = { (union xioaddr_desc *)&xioendpoint_abstract_recvfrom1, NULL };
static const struct xioaddr_endpoint_desc xioendpoint_abstract_recv1 = { XIOADDR_SYS, "abstract-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_abstract_recv, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
const union xioaddr_desc *xioaddrs_abstract_recv[] = { (union xioaddr_desc *)&xioendpoint_abstract_recv1, NULL };
static const struct xioaddr_endpoint_desc xioendpoint_abstract_client1 = { XIOADDR_SYS, "abstract-client", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_abstract_client, PF_UNIX, 0, 0 HELP(":<filename>") };
const union xioaddr_desc *xioaddrs_abstract_client[] = { (union xioaddr_desc *)&xioendpoint_abstract_client1, NULL };
#endif /* WITH_ABSTRACT_UNIXSOCKET */ #endif /* WITH_ABSTRACT_UNIXSOCKET */
const struct optdesc opt_unix_tightsocklen = { "unix-tightsocklen", "tightsocklen", OPT_UNIX_TIGHTSOCKLEN, GROUP_SOCK_UNIX, PH_INIT, TYPE_BOOL, OFUNC_SPEC, 0, 0 }; const struct optdesc opt_unix_tightsocklen = { "unix-tightsocklen", "tightsocklen", OPT_UNIX_TIGHTSOCKLEN, GROUP_SOCK_UNIX, PH_INIT, TYPE_BOOL, OFUNC_SPEC, 0, 0 };
@ -133,8 +145,6 @@ static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, i
xfd->opt_unlink_close = true; xfd->opt_unlink_close = true;
} }
xfd->howtoend = END_SHUTDOWN;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_EARLY); applyopts(-1, opts, PH_EARLY);
@ -242,8 +252,6 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i
uslen = socket_init(pf, &us); uslen = socket_init(pf, &us);
xfd->salen = socket_init(pf, &xfd->peersa); xfd->salen = socket_init(pf, &xfd->peersa);
xfd->howtoend = END_SHUTDOWN;
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
@ -299,7 +307,6 @@ int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts,
name = argv[1]; name = argv[1];
uslen = xiosetunix(&us, name, false, tight); uslen = xiosetunix(&us, name, false, tight);
xfd->stream.howtoend = END_NONE;
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0); retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0);
retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early); retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
@ -406,7 +413,6 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
} }
xfd->howtoend = END_SHUTDOWN;
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
uslen = socket_init(pf, &us); uslen = socket_init(pf, &us);
@ -487,8 +493,6 @@ static int xioopen_abstract_listen(int argc, const char *argv[], struct opt *opt
name = argv[1]; name = argv[1];
uslen = xiosetunix(&us, name, true, tight); uslen = xiosetunix(&us, name, true, tight);
xfd->howtoend = END_SHUTDOWN;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_EARLY); applyopts(-1, opts, PH_EARLY);
@ -574,8 +578,6 @@ static int xioopen_abstract_sendto(int argc, const char *argv[], struct opt *opt
uslen = socket_init(pf, &us); uslen = socket_init(pf, &us);
xfd->salen = socket_init(pf, &xfd->peersa); xfd->salen = socket_init(pf, &xfd->peersa);
xfd->howtoend = END_SHUTDOWN;
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
@ -620,7 +622,6 @@ int xioopen_abstract_recvfrom(int argc, const char *argv[], struct opt *opts,
name = argv[1]; name = argv[1];
uslen = xiosetunix(&us, name, true, tight); uslen = xiosetunix(&us, name, true, tight);
xfd->stream.howtoend = END_NONE;
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0); retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0);
@ -685,7 +686,6 @@ static int xioopen_abstract_client(int argc, const char *argv[], struct opt *opt
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
} }
xfd->howtoend = END_SHUTDOWN;
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
uslen = socket_init(pf, &us); uslen = socket_init(pf, &us);

View file

@ -5,18 +5,18 @@
#ifndef __xio_unix_h_included #ifndef __xio_unix_h_included
#define __xio_unix_h_included 1 #define __xio_unix_h_included 1
extern const struct addrdesc addr_unix_connect; extern const union xioaddr_desc *xioaddrs_unix_connect[];
extern const struct addrdesc addr_unix_listen; extern const union xioaddr_desc *xioaddrs_unix_listen[];
extern const struct addrdesc addr_unix_sendto; extern const union xioaddr_desc *xioaddrs_unix_sendto[];
extern const struct addrdesc addr_unix_recvfrom; extern const union xioaddr_desc *xioaddrs_unix_recvfrom[];
extern const struct addrdesc addr_unix_recv; extern const union xioaddr_desc *xioaddrs_unix_recv[];
extern const struct addrdesc addr_unix_client; extern const union xioaddr_desc *xioaddrs_unix_client[];
extern const struct addrdesc xioaddr_abstract_connect; extern const union xioaddr_desc *xioaddrs_abstract_connect[];
extern const struct addrdesc xioaddr_abstract_listen; extern const union xioaddr_desc *xioaddrs_abstract_listen[];
extern const struct addrdesc xioaddr_abstract_sendto; extern const union xioaddr_desc *xioaddrs_abstract_sendto[];
extern const struct addrdesc xioaddr_abstract_recvfrom; extern const union xioaddr_desc *xioaddrs_abstract_recvfrom[];
extern const struct addrdesc xioaddr_abstract_recv; extern const union xioaddr_desc *xioaddrs_abstract_recv[];
extern const struct addrdesc xioaddr_abstract_client; extern const union xioaddr_desc *xioaddrs_abstract_client[];
extern const struct optdesc opt_unix_tightsocklen; extern const struct optdesc opt_unix_tightsocklen;

309
xio.h
View file

@ -19,7 +19,7 @@
#define LINETERM_CR 1 #define LINETERM_CR 1
#define LINETERM_CRNL 2 #define LINETERM_CRNL 2
struct addrdesc; union xioaddr_desc;
struct opt; struct opt;
/* the flags argument of xioopen */ /* the flags argument of xioopen */
@ -27,18 +27,37 @@ struct opt;
#define XIO_WRONLY O_WRONLY /* asserted to be 1 */ #define XIO_WRONLY O_WRONLY /* asserted to be 1 */
#define XIO_RDWR O_RDWR /* asserted to be 2 */ #define XIO_RDWR O_RDWR /* asserted to be 2 */
#define XIO_ACCMODE O_ACCMODE /* must be 3 */ #define XIO_ACCMODE O_ACCMODE /* must be 3 */
#define XIO_MAYFORK 4 /* address is allowed to fork the program (fork) */ /* 3 is undefined */
#define XIO_MAYCHILD 8 /* address is allowed to fork off a child (exec)*/ #define XIO_MAYFORK 4 /* address is allowed to fork the program (fork),
especially with listen and connect addresses */
#define XIO_MAYCHILD 8 /* address is allowed to fork off a child that
exec's another program or calls system() */
#define XIO_MAYEXEC 16 /* address is allowed to exec a prog (exec+nofork) */ #define XIO_MAYEXEC 16 /* address is allowed to exec a prog (exec+nofork) */
#define XIO_MAYCONVERT 32 /* address is allowed to perform modifications on the #define XIO_MAYCONVERT 32 /* address is allowed to perform modifications on the
stream data, e.g. SSL, REALDINE; CRLF */ stream data, e.g. SSL, READLINE; CRLF */
#define XIO_MAYCHAIN 64 /* address is allowed to consist of a chain of
subaddresses that are handled by socat
subprocesses */
#define XIO_EMBEDDED 256 /* address is nonterminal */
#define XIO_MAYALL INT_MAX /* all features enabled */
/* the status flags of xiofile_t */ /* the status flags of xiofile_t */
#define XIO_DOESFORK XIO_MAYFORK #define XIO_DOESFORK XIO_MAYFORK
#define XIO_DOESCHILD XIO_MAYCHILD #define XIO_DOESCHILD XIO_MAYCHILD
#define XIO_DOESEXEC XIO_MAYEXEC #define XIO_DOESEXEC XIO_MAYEXEC
#define XIO_DOESCONVERT XIO_MAYCONVERT #define XIO_DOESCONVERT XIO_MAYCONVERT
#define XIO_DOESCHAIN XIO_MAYCHAIN
/* sometimes we use a set of allowed direction(s), a bit pattern */
#define XIOBIT_RDONLY (1<<XIO_RDONLY)
#define XIOBIT_WRONLY (1<<XIO_WRONLY)
#define XIOBIT_RDWR (1<<XIO_RDWR)
#define XIOBIT_ALL (XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR)
#define XIOBIT_ALLRD (XIOBIT_RDONLY|XIOBIT_RDWR)
#define XIOBIT_ALLWR (XIOBIT_WRONLY|XIOBIT_RDWR)
#define XIOBIT_ONE (XIOBIT_RDONLY|XIOBIT_WRONLY)
/* reverse the direction pattern */
#define XIOBIT_REVERSE(x) (((x)&XIOBIT_RDWR)|(((x)&XIOBIT_RDONLY)?XIOBIT_WRONLY:0)|(((x)&XIOBIT_WRONLY)?XIOBIT_RDONLY:0))
/* methods for reading and writing, and for related checks */ /* methods for reading and writing, and for related checks */
#define XIODATA_READMASK 0xf000 /* mask for basic r/w method */ #define XIODATA_READMASK 0xf000 /* mask for basic r/w method */
@ -47,6 +66,7 @@ struct opt;
#define XIOREAD_PTY 0x4000 /* handle EIO */ #define XIOREAD_PTY 0x4000 /* handle EIO */
#define XIOREAD_READLINE 0x5000 /* ... */ #define XIOREAD_READLINE 0x5000 /* ... */
#define XIOREAD_OPENSSL 0x6000 /* SSL_read() */ #define XIOREAD_OPENSSL 0x6000 /* SSL_read() */
#define XIOREAD_TEST 0x7000 /* xioread_test() */
#define XIODATA_WRITEMASK 0x0f00 /* mask for basic r/w method */ #define XIODATA_WRITEMASK 0x0f00 /* mask for basic r/w method */
#define XIOWRITE_STREAM 0x0100 /* write() (default) */ #define XIOWRITE_STREAM 0x0100 /* write() (default) */
#define XIOWRITE_SENDTO 0x0200 /* sendto() */ #define XIOWRITE_SENDTO 0x0200 /* sendto() */
@ -54,6 +74,8 @@ struct opt;
#define XIOWRITE_2PIPE 0x0400 /* write() to alternate (2pipe) Fd */ #define XIOWRITE_2PIPE 0x0400 /* write() to alternate (2pipe) Fd */
#define XIOWRITE_READLINE 0x0500 /* check for prompt */ #define XIOWRITE_READLINE 0x0500 /* check for prompt */
#define XIOWRITE_OPENSSL 0x0600 /* SSL_write() */ #define XIOWRITE_OPENSSL 0x0600 /* SSL_write() */
#define XIOWRITE_TEST 0x0700 /* xiowrite_test() */
#define XIOWRITE_TESTREV 0x0800 /* xiowrite_testrev() */
/* modifiers to XIODATA_READ_RECV */ /* modifiers to XIODATA_READ_RECV */
#define XIOREAD_RECV_CHECKPORT 0x0001 /* recv, check peer port */ #define XIOREAD_RECV_CHECKPORT 0x0001 /* recv, check peer port */
#define XIOREAD_RECV_CHECKADDR 0x0002 /* recv, check peer address */ #define XIOREAD_RECV_CHECKADDR 0x0002 /* recv, check peer address */
@ -76,7 +98,46 @@ struct opt;
#define XIODATA_PTY (XIOREAD_PTY|XIOWRITE_STREAM) #define XIODATA_PTY (XIOREAD_PTY|XIOWRITE_STREAM)
#define XIODATA_READLINE (XIOREAD_READLINE|XIOWRITE_STREAM) #define XIODATA_READLINE (XIOREAD_READLINE|XIOWRITE_STREAM)
#define XIODATA_OPENSSL (XIOREAD_OPENSSL|XIOWRITE_OPENSSL) #define XIODATA_OPENSSL (XIOREAD_OPENSSL|XIOWRITE_OPENSSL)
#define XIODATA_TEST (XIOREAD_TEST|XIOWRITE_TEST)
#define XIODATA_TESTUNI XIOWRITE_TEST
#define XIODATA_TESTREV XIOWRITE_TESTREV
/* XIOSHUT_* define the actions on shutdown of the address */
/* */
#define XIOSHUTRD_MASK 0x00f0
#define XIOSHUTWR_MASK 0x000f
#define XIOSHUTSPEC_MASK 0xff00 /* specific action */
#define XIOSHUTRD_UNSPEC 0x0000
#define XIOSHUTWR_UNSPEC 0x0000
#define XIOSHUTRD_NONE 0x0010 /* no action - e.g. stdin */
#define XIOSHUTWR_NONE 0x0001 /* no action - e.g. stdout */
#define XIOSHUTRD_CLOSE 0x0020 /* close() */
#define XIOSHUTWR_CLOSE 0x0002 /* close() */
#define XIOSHUTRD_DOWN 0x0030 /* shutdown(, SHUT_RD) */
#define XIOSHUTWR_DOWN 0x0003 /* shutdown(, SHUT_WR) */
#define XIOSHUTRD_SIGHUP 0x0040 /* kill sub process */
#define XIOSHUTWR_SIGHUP 0x0004 /* flush sub process with SIGHPUP */
#define XIOSHUTRD_SIGTERM 0x0050 /* kill sub process with SIGTERM */
#define XIOSHUTWR_SIGTERM 0x0005 /* kill sub process with SIGTERM */
#define XIOSHUTWR_SIGKILL 0x0006 /* kill sub process with SIGKILL */
#define XIOSHUT_UNSPEC (XIOSHUTRD_UNSPEC|XIOSHUTWR_UNSPEC)
#define XIOSHUT_NONE (XIOSHUTRD_NONE|XIOSHUTWR_NONE)
#define XIOSHUT_CLOSE (XIOSHUTRD_CLOSE|XIOSHUTWR_CLOSE)
#define XIOSHUT_DOWN (XIOSHUTRD_DOWN|XIOSHUTWR_DOWN)
#define XIOSHUT_KILL (XIOSHUTRD_KILL|XIOSHUTWR_KILL)
#define XIOSHUT_OPENSSL 0x0100 /* specific action on openssl */
/*!!!*/
#define XIOCLOSE_UNSPEC 0x0000 /* after init, when no end-close... option */
#define XIOCLOSE_NONE 0x0001 /* no action */
#define XIOCLOSE_CLOSE 0x0002 /* close() */
#define XIOCLOSE_SIGTERM 0x0003 /* send SIGTERM to sub process */
#define XIOCLOSE_SIGKILL 0x0004 /* send SIGKILL to sub process */
#define XIOCLOSE_CLOSE_SIGTERM 0x0005 /* close fd, then send SIGTERM */
#define XIOCLOSE_CLOSE_SIGKILL 0x0006 /* close fd, then send SIGKILL */
#define XIOCLOSE_SLEEP_SIGTERM 0x0007 /* short sleep, then SIGTERM */
#define XIOCLOSE_OPENSSL 0x0100
#define XIOCLOSE_READLINE 0x0101
/* these are the values allowed for the "enum xiotag tag" flag of the "struct /* these are the values allowed for the "enum xiotag tag" flag of the "struct
single" and "union bipipe" (xiofile_t) structures. */ single" and "union bipipe" (xiofile_t) structures. */
@ -89,6 +150,88 @@ enum xiotag {
streams */ streams */
} ; } ;
union bipipe;
#define XIOADDR_ENDPOINT 0 /* endpoint address */
#define XIOADDR_INTER 1 /* inter address */
#define XIOADDR_SYS XIOADDR_ENDPOINT
#define XIOADDR_PROT XIOADDR_INTER
struct xioaddr_inter_desc {
int tag; /* 0: endpoint addr; 1: inter addr */
const char *defname; /* main (canonical) name of address */
int numparams; /* number of required parameters */
int leftdirs; /* set of data directions supported on left side:
e.g. XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR */
unsigned groups;
int howtoshut;
int howtoclose;
int (*func)(int argc, const char *argv[], struct opt *opts, int rw, union bipipe *fd, unsigned groups,
int arg1, int arg2, int arg3);
int arg1;
int arg2;
int arg3;
int rightdirs;
#if WITH_HELP
const char *syntax;
#endif
} ;
struct xioaddr_endpoint_desc {
int tag; /* 0: endpoint addr; 1: inter addr */
const char *defname; /* main (canonical) name of address */
int numparams; /* number of required parameters */
int leftdirs;
unsigned groups;
int howtoshut;
int howtoclose;
int (*func)(int argc, const char *argv[], struct opt *opts, int rw, union bipipe *fd, unsigned groups,
int arg1, int arg2, int arg3);
int arg1;
int arg2;
int arg3;
#if WITH_HELP
const char *syntax;
#endif
} ;
struct xioaddr_common_desc {
int tag; /* 0: endpoint addr; 1: inter addr */
const char *defname; /* main (canonical) name of address */
int numparams; /* number of required parameters */
int leftdirs;
unsigned groups;
int howtoshut;
int howtoclose;
} ;
union xioaddr_desc {
int tag; /* 0: endpoint addr; 1: inter addr */
struct xioaddr_common_desc common_desc;
struct xioaddr_inter_desc inter_desc;
struct xioaddr_endpoint_desc endpoint_desc;
} ;
union xioaddr_descp {
struct xioaddr_common_desc *common_desc;
int *tag; /* 0: endpoint addr; 1: inter addr */
struct xioaddr_inter_desc *inter_desc;
struct xioaddr_endpoint_desc *endpoint_desc;
} ;
/*!!! this to xio-sockd4.h */
struct socks4head {
uint8_t version;
uint8_t action;
uint16_t port;
uint32_t dest;
} ;
/* global XIO options/parameters */ /* global XIO options/parameters */
typedef struct { typedef struct {
bool strictopts; bool strictopts;
@ -97,11 +240,22 @@ typedef struct {
const char *optionsep; const char *optionsep;
char ip4portsep; char ip4portsep;
char ip6portsep; /* do not change, might be hardcoded somewhere! */ char ip6portsep; /* do not change, might be hardcoded somewhere! */
char logopt; /* 'm' means "switch to syslog when entering daemon mode" */
const char *syslogfac; /* syslog facility (only with mixed mode) */ const char *syslogfac; /* syslog facility (only with mixed mode) */
char default_ip; /* default prot.fam for IP based listen ('4' or '6') */ char default_ip; /* default prot.fam for IP based listen ('4' or '6') */
char preferred_ip; /* preferred prot.fam. for name resolution ('0' for char preferred_ip; /* preferred prot.fam. for name resolution ('0' for
unspecified, '4', or '6') */ unspecified, '4', or '6') */
char *reversechar;
char *chainsep;
size_t bufsiz;
bool verbose;
bool verbhex;
bool debug;
char logopt; /* y..syslog; s..stderr; f..file; m..mixed */
struct timeval total_timeout;/* when nothing happens, die after seconds */
struct timeval pollintv; /* with ignoreeof, reread after seconds */
struct timeval closwait; /* after close of x, die after seconds */
bool lefttoright; /* first addr ro, second addr wo */
bool righttoleft; /* first addr wo, second addr ro */
} xioopts_t; } xioopts_t;
/* pack the description of a lock file */ /* pack the description of a lock file */
@ -111,14 +265,12 @@ typedef struct {
struct timespec intervall; /* polling intervall */ struct timespec intervall; /* polling intervall */
} xiolock_t; } xiolock_t;
extern xioopts_t xioopts;
#define MAXARGV 8 #define MAXARGV 8
/* a non-dual file descriptor */ /* a non-dual file descriptor */
typedef struct single { typedef struct single {
enum xiotag tag; /* see enum xiotag */ enum xiotag tag; /* see enum xiotag */
const struct addrdesc *addr; const union xioaddr_desc *addrdesc;
int flags; int flags;
/* until here, keep consistent with bipipe.common !!! */ /* until here, keep consistent with bipipe.common !!! */
#if WITH_RETRY #if WITH_RETRY
@ -136,26 +288,41 @@ typedef struct single {
size_t actbytes; /* so many bytes still to be read (when readbytes!=0)*/ size_t actbytes; /* so many bytes still to be read (when readbytes!=0)*/
xiolock_t lock; /* parameters of lockfile */ xiolock_t lock; /* parameters of lockfile */
bool havelock; /* we are happy owner of the above lock */ bool havelock; /* we are happy owner of the above lock */
bool cool_write; /* downlevel EPIPE, ECONNRESET to notice */
/* until here, keep consistent with bipipe.dual ! */ /* until here, keep consistent with bipipe.dual ! */
int reverse; /* valid during parse and overload, before open:
will this (inter) address be integrated forward or
reverse? */
const union xioaddr_desc **addrdescs;
/* valid after parse, before overload:
the list of possible address descriptors derived
from addr keyword, one of which will be selected by
context and num of parameters */
int closing; /* 0..write channel is up, 1..just shutdown write ch.,
2..counting down closing timeout, 3..no more write
possible */
bool cool_write; /* downlevel EPIPE, ECONNRESET to notice */
int argc; /* number of fields in argv */ int argc; /* number of fields in argv */
const char *argv[MAXARGV]; /* address keyword, required args */ const char *argv[MAXARGV]; /* address keyword, required args */
struct opt *opts; /* the options of this address */ struct opt *opts; /* the options of this address */
int lineterm; /* 0..dont touch; 1..CR; 2..CRNL on extern data */ int lineterm; /* 0..dont touch; 1..CR; 2..CRNL on extern data */
int fd; int fd1;
int fd2;
enum {
FDTYPE_SINGLE, /* only fd1 is in use, for reading and/or writing */
FDTYPE_DOUBLE /* fd2 is in use too - for writing */
} fdtype;
pid_t subaddrpid; /* pid of subaddress (process handling next addr in
chain) */
int subaddrstat; /* state of subaddress process
0...no sub address process
1...running
-1...ended (aborted?) */
int subaddrexit; /* if subaddstat==-1: exit code of sub process */
bool opt_unlink_close; /* option unlink_close */ bool opt_unlink_close; /* option unlink_close */
char *unlink_close; /* name of a symlink or unix socket to be removed */ char *unlink_close; /* name of a symlink or unix socket to be removed */
int dtype; int dtype;
enum { int howtoshut; /* method for shutting down xfds */
END_UNSPEC, /* after init, when no end-close... option */ int howtoclose; /* method for closing xfds */
END_NONE, /* no action */
END_CLOSE, /* close() */
END_SHUTDOWN, /* shutdown() */
END_UNLINK, /* unlink() */
END_KILL, /* has subprocess */
END_CLOSE_KILL, /* first close fd, then kill subprocess */
END_SHUTDOWN_KILL /* first shutdown fd, then kill subprocess */
} howtoend;
#if _WITH_SOCKET #if _WITH_SOCKET
union sockaddr_union peersa; union sockaddr_union peersa;
socklen_t salen; socklen_t salen;
@ -164,13 +331,19 @@ typedef struct single {
bool ttyvalid; /* the following struct is valid */ bool ttyvalid; /* the following struct is valid */
struct termios savetty; /* save orig tty settings for later restore */ struct termios savetty; /* save orig tty settings for later restore */
#endif /* WITH_TERMIOS */ #endif /* WITH_TERMIOS */
const char *name; /* only with END_UNLINK */ /*0 const char *name;*/ /* only with END_UNLINK */
struct { /* this was for exec only, now for embedded */
pid_t pid; /* child PID, with EXEC: */
int (*sigchild)(struct single *); /* callback after sigchild */ int (*sigchild)(struct single *); /* callback after sigchild */
} child;
pid_t ppid; /* parent pid, only if we send it signals */ pid_t ppid; /* parent pid, only if we send it signals */
pthread_t subthread; /* thread handling next inter-addr in chain */
union { union {
#if 0
struct { struct {
int fdout; /* use fd for output */ int fdout; /* use fd for output */
} bipipe; } bipipe;
#endif
#if _WITH_SOCKET #if _WITH_SOCKET
struct { struct {
struct timeval connect_timeout; /* how long to hang in connect() */ struct timeval connect_timeout; /* how long to hang in connect() */
@ -213,6 +386,37 @@ typedef struct single {
#endif #endif
} readline; } readline;
#endif /* WITH_READLINE */ #endif /* WITH_READLINE */
#if WITH_SOCKS4_SERVER
struct {
int state; /* state of socks4 protocol negotiation */
/* we cannot rely on all request data arriving at once */
struct socks4head head;
char *userid;
char *hostname; /* socks4a only */
/* the following structs are an experiment for future synchronization
mechanisms */
struct {
size_t canrecv;
size_t wantwrite;
void *inbuff;
size_t inbuflen; /* length of buffer */
size_t bytes; /* current bytes in buffer */
} proto;
struct {
size_t canrecv;
size_t wantwrite;
} peer_proto;
struct {
size_t canrecv;
size_t wantwrite;
int _errno;
} data;
struct {
size_t canrecv;
size_t wantwrite;
} peer_data;
} socks4d;
#endif /* WITH_SOCKS4_SERVER */
#if WITH_OPENSSL #if WITH_OPENSSL
struct { struct {
struct timeval connect_timeout; /* how long to hang in connect() */ struct timeval connect_timeout; /* how long to hang in connect() */
@ -225,6 +429,13 @@ typedef struct single {
short iff_opts[2]; /* ifr flags, using OFUNC_OFFSET_MASKS */ short iff_opts[2]; /* ifr flags, using OFUNC_OFFSET_MASKS */
} tun; } tun;
#endif /* WITH_TUN */ #endif /* WITH_TUN */
#if _WITH_GZIP
struct {
gzFile in; /* for reading (uncompressing from stream to API) */
gzFile out; /* for writing (compressing from API to stream) */
int level;
} gzip;
#endif /* _WITH_GZIP */
} para; } para;
} xiosingle_t; } xiosingle_t;
@ -242,13 +453,13 @@ typedef union bipipe {
enum xiotag tag; enum xiotag tag;
struct { struct {
enum xiotag tag; enum xiotag tag;
const struct addrdesc *addr; const union xioaddr_desc *addrdesc;
int flags; int flags;
} common; } common;
struct single stream; struct single stream;
struct { struct {
enum xiotag tag; enum xiotag tag;
const struct addrdesc *addr; const union xioaddr_desc *addrdesc;
int flags; /* compatible to fcntl(.., F_GETFL, ..) */ int flags; /* compatible to fcntl(.., F_GETFL, ..) */
#if WITH_RETRY #if WITH_RETRY
unsigned retry; /* retry opening this many times */ unsigned retry; /* retry opening this many times */
@ -262,31 +473,19 @@ typedef union bipipe {
size_t actbytes; /* so many bytes still to be read */ size_t actbytes; /* so many bytes still to be read */
xiolock_t lock; /* parameters of lockfile */ xiolock_t lock; /* parameters of lockfile */
bool havelock; /* we are happy owner of the above lock */ bool havelock; /* we are happy owner of the above lock */
/* until here, keep consistent with struct single ! */
xiosingle_t *stream[2]; /* input stream, output stream */ xiosingle_t *stream[2]; /* input stream, output stream */
} dual; } dual;
} xiofile_t; } xiofile_t;
struct addrdesc {
const char *defname; /* main (canonical) name of address */
int directions; /* 1..read, 2..write, 3..both */
int (*func)(int argc, const char *argv[], struct opt *opts, int rw, xiofile_t *fd, unsigned groups,
int arg1, int arg2, int arg3);
unsigned groups;
int arg1;
int arg2;
int arg3;
#if WITH_HELP
const char *syntax;
#endif
} ;
#define XIO_WRITABLE(s) (((s)->common.flags+1)&2) #define XIO_WRITABLE(s) (((s)->common.flags+1)&2)
#define XIO_READABLE(s) (((s)->common.flags+1)&1) #define XIO_READABLE(s) (((s)->common.flags+1)&1)
#define XIO_RDSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]:&(s)->stream) #define XIO_RDSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]:&(s)->stream)
#define XIO_WRSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[1]:&(s)->stream) #define XIO_WRSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[1]:&(s)->stream)
#define XIO_GETRDFD(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]->fd:(s)->stream.fd) #define XIO_GETRDFD(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]->fd1:(s)->stream.fd1)
#define XIO_GETWRFD(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[1]->fd:(((s)->stream.dtype&XIODATA_WRITEMASK)==XIOWRITE_2PIPE)?(s)->stream.para.exec.fdout:(((s)->stream.dtype&XIODATA_WRITEMASK)==XIOWRITE_PIPE)?(s)->stream.para.bipipe.fdout:(s)->stream.fd) #define _XIO_GETWRFD(s) (((s)->fdtype==FDTYPE_DOUBLE)?(s)->fd2:(s)->fd1)
#define XIO_GETWRFD(s) (((s)->tag==XIO_TAG_DUAL)?_XIO_GETWRFD((s)->dual.stream[1]):_XIO_GETWRFD(&(s)->stream))
#define XIO_EOF(s) (XIO_RDSTREAM(s)->eof && !XIO_RDSTREAM(s)->ignoreeof) #define XIO_EOF(s) (XIO_RDSTREAM(s)->eof && !XIO_RDSTREAM(s)->ignoreeof)
typedef unsigned long flags_t; typedef unsigned long flags_t;
@ -357,6 +556,12 @@ struct opt {
union integral value; union integral value;
} ; } ;
/* with threading, the arguments indirectly passed to xioengine() */
struct threadarg_struct {
xiofile_t *xfd1;
xiofile_t *xfd2;
} ;
extern const char *PIPESEP; extern const char *PIPESEP;
extern xiofile_t *sock[XIO_MAXSOCK]; extern xiofile_t *sock[XIO_MAXSOCK];
@ -372,33 +577,39 @@ extern xiofile_t *sock[XIO_MAXSOCK];
#define STAT_NORETRY -3 /* address syntax error, not implemented etc; #define STAT_NORETRY -3 /* address syntax error, not implemented etc;
not even by external changes correctable */ not even by external changes correctable */
extern int xioinitialize(void); extern int xioinitialize(int xioflags);
extern int xio_forked_inchild(void); extern int xio_forked_inchild(void);
extern int xiosetopt(char what, const char *arg); extern int xiosetopt(char what, const char *arg);
extern int xioinqopt(char what, char *arg, size_t n); extern int xioinqopt(char what, char *arg, size_t n);
extern xiofile_t *xioopen(const char *args, int flags); extern xiofile_t *xioopen(const char *args, int xioflags);
extern int xioopensingle(char *addr, struct single *xfd, int xioflags); extern xiofile_t *xioopenx(const char *addr, int xioflags, int infd, int outfd);extern int xiosocketpair(xiofile_t **xfd1p, xiofile_t **xfd2p, int how, ...);
extern int xioopensingle(char *addr, xiosingle_t *fd, int xioflags);
extern int xioopenhelp(FILE *of, int level); extern int xioopenhelp(FILE *of, int level);
/* must be outside function for use by childdied handler */ /* must be outside function for use by childdied handler */
extern xiofile_t *sock1, *sock2; extern xiofile_t *xioallocfd(void);
extern pid_t diedunknown1; /* child died before it is registered */ extern void xiofreefd(xiofile_t *xfd);
extern pid_t diedunknown2;
extern pid_t diedunknown3;
extern pid_t diedunknown4;
extern int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *));
extern int xio_opt_signal(pid_t pid, int signum); extern int xio_opt_signal(pid_t pid, int signum);
extern void childdied(int signum);
extern void *xioengine(void *thread_arg);
extern int _socat(xiofile_t *xfd1, xiofile_t *xfd2);
extern ssize_t xioread(xiofile_t *sock1, void *buff, size_t bufsiz); extern ssize_t xioread(xiofile_t *sock1, void *buff, size_t bufsiz);
extern ssize_t xiopending(xiofile_t *sock1); extern ssize_t xiopending(xiofile_t *sock1);
extern ssize_t xiowrite(xiofile_t *sock1, const void *buff, size_t bufsiz); extern ssize_t xiowrite(xiofile_t *sock1, const void *buff, size_t bufsiz);
extern int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
unsigned char **buff, size_t bufsiz, bool righttoleft);
extern int xioshutdown(xiofile_t *sock, int how); extern int xioshutdown(xiofile_t *sock, int how);
extern int xioclose(xiofile_t *sock); extern int xioclose(xiofile_t *sock);
extern void xioexit(void); extern void xioexit(void);
extern int (*xiohook_newchild)(void); /* xio calls this function from a new child process */ extern int (*xiohook_newchild)(void); /* xio calls this function from a new child process */
extern int socat_sigchild(struct single *file);
extern xioopts_t xioopts, *xioparams;
#endif /* !defined(__xio_h_included) */ #endif /* !defined(__xio_h_included) */

View file

@ -21,63 +21,82 @@ int xioclose1(struct single *pipe) {
return -1; return -1;
} }
switch (pipe->howtoclose) {
#if WITH_READLINE #if WITH_READLINE
if ((pipe->dtype & XIODATA_MASK) == XIODATA_READLINE) { case XIOCLOSE_READLINE:
Write_history(pipe->para.readline.history_file); Write_history(pipe->para.readline.history_file);
/*xiotermios_setflag(pipe->fd, 3, ECHO|ICANON);*/ /* error when pty closed */ /*xiotermios_setflag(pipe->fd, 3, ECHO|ICANON);*/ /* error when pty closed */
} break;
#endif /* WITH_READLINE */ #endif /* WITH_READLINE */
#if WITH_OPENSSL #if WITH_OPENSSL
if ((pipe->dtype & XIODATA_MASK) == XIODATA_OPENSSL) { case XIOCLOSE_OPENSSL:
if (pipe->para.openssl.ssl) { if (pipe->para.openssl.ssl) {
/* e.g. on TCP connection refused, we do not yet have this set */ /* e.g. on TCP connection refused, we do not yet have this set */
sycSSL_shutdown(pipe->para.openssl.ssl); sycSSL_shutdown(pipe->para.openssl.ssl);
sycSSL_free(pipe->para.openssl.ssl); sycSSL_free(pipe->para.openssl.ssl);
pipe->para.openssl.ssl = NULL; pipe->para.openssl.ssl = NULL;
} }
Close(pipe->fd); pipe->fd = -1; Close(pipe->fd1); pipe->fd1 = -1;
Close(pipe->fd2); pipe->fd2 = -1;
if (pipe->para.openssl.ctx) { if (pipe->para.openssl.ctx) {
sycSSL_CTX_free(pipe->para.openssl.ctx); sycSSL_CTX_free(pipe->para.openssl.ctx);
pipe->para.openssl.ctx = NULL; pipe->para.openssl.ctx = NULL;
} }
} else break;
#endif /* WITH_OPENSSL */ #endif /* WITH_OPENSSL */
#if WITH_TERMIOS #if WITH_TERMIOS
if (pipe->ttyvalid) { if (pipe->ttyvalid) {
if (Tcsetattr(pipe->fd, 0, &pipe->savetty) < 0) { if (Tcsetattr(pipe->fd1, 0, &pipe->savetty) < 0) {
Warn2("cannot restore terminal settings on fd %d: %s", Warn2("cannot restore terminal settings on fd %d: %s",
pipe->fd, strerror(errno)); pipe->fd1, strerror(errno));
} }
} }
#endif /* WITH_TERMIOS */ #endif /* WITH_TERMIOS */
if (pipe->fd >= 0) {
switch (pipe->howtoend) { case XIOCLOSE_SIGTERM:
case END_KILL: case END_SHUTDOWN_KILL: case END_CLOSE_KILL: if (pipe->child.pid > 0) {
if (pipe->para.exec.pid > 0) { if (Kill(pipe->child.pid, SIGTERM) < 0) {
if (Kill(pipe->para.exec.pid, SIGTERM) < 0) {
Msg2(errno==ESRCH?E_INFO:E_WARN, "kill(%d, SIGTERM): %s", Msg2(errno==ESRCH?E_INFO:E_WARN, "kill(%d, SIGTERM): %s",
pipe->para.exec.pid, strerror(errno)); pipe->child.pid, strerror(errno));
} }
} }
break;
case XIOCLOSE_CLOSE_SIGTERM:
if (pipe->child.pid > 0) {
if (Kill(pipe->child.pid, SIGTERM) < 0) {
Msg2(errno==ESRCH?E_INFO:E_WARN, "kill(%d, SIGTERM): %s",
pipe->child.pid, strerror(errno));
}
}
/*PASSTHROUGH*/
case XIOCLOSE_CLOSE:
if (pipe->fd1 >= 0) {
if (Close(pipe->fd1) < 0) {
Info2("close(%d): %s", pipe->fd1, strerror(errno));
}
}
break;
case XIOCLOSE_SLEEP_SIGTERM:
Sleep(1);
if (pipe->child.pid > 0) {
if (Kill(pipe->child.pid, SIGTERM) < 0) {
Msg2(errno==ESRCH?E_INFO:E_WARN, "kill(%d, SIGTERM): %s",
pipe->child.pid, strerror(errno));
}
}
break;
case XIOCLOSE_NONE:
break;
default: default:
Error2("xioclose(): bad end action 0x%x on 0x%x", pipe->howtoclose, pipe);
break; break;
} }
switch (pipe->howtoend) {
case END_CLOSE: case END_CLOSE_KILL:
if (Close(pipe->fd) < 0) {
Info2("close(%d): %s", pipe->fd, strerror(errno)); } break;
#if WITH_SOCKET
case END_SHUTDOWN: case END_SHUTDOWN_KILL:
if (Shutdown(pipe->fd, 2) < 0) {
Info3("shutdown(%d, %d): %s", pipe->fd, 2, strerror(errno)); }
break;
#endif /* WITH_SOCKET */
case END_UNLINK: if (Unlink((const char *)pipe->name) < 0) {
Warn2("unlink(\"%s\"): %s", pipe->name, strerror(errno)); }
break;
case END_NONE: default: break;
}
}
/* unlock */ /* unlock */
if (pipe->havelock) { if (pipe->havelock) {
@ -98,6 +117,7 @@ int xioclose1(struct single *pipe) {
/* close the xio fd */ /* close the xio fd */
int xioclose(xiofile_t *file) { int xioclose(xiofile_t *file) {
xiofile_t *xfd = file;
int result; int result;
if (file->tag == XIO_TAG_INVALID) { if (file->tag == XIO_TAG_INVALID) {
@ -113,6 +133,9 @@ int xioclose(xiofile_t *file) {
} else { } else {
result = xioclose1(&file->stream); result = xioclose1(&file->stream);
} }
if (xfd->stream.subthread != 0) {
Pthread_join(xfd->stream.subthread, NULL);
}
return result; return result;
} }

View file

@ -21,23 +21,26 @@
#endif #endif
#if WITH_SOCKS4A #if WITH_SOCKS4A
# define WITH_SOCKS4 1 # define _WITH_SOCKS4 1
#endif #endif
#if WITH_SOCKS4 || WITH_PROXY #if WITH_SOCKS4 || WITH_SOCKS5 || WITH_PROXY
# define WITH_TCP 1 # define _WITH_TCP 1
# define WITH_IP4 1 /* currently this socks implementation does not work # define _WITH_IP4 1 /* currently this socks implementation does not work
with IP6 */ with IP6 */
#endif #endif
#if WITH_OPENSSL #if 0
# define WITH_TCP 1 #if !defined(HAVE_NETINET_IP6_H)
# define WITH_IP4 1 # undef WITH_IP6
#endif
#endif #endif
#if WITH_IP6 #if WITH_OPENSSL
# if !defined(HAVE_NETINET_IP6_H) # define _WITH_TCP 1
# undef WITH_IP6 # define _WITH_IP4 1
# if WITH_IP6
# define _WITH_IP6 1
# endif # endif
#endif #endif
@ -47,7 +50,11 @@
# endif # endif
#endif #endif
#if WITH_UNIX || WITH_IP4 || WITH_IP6 || WITH_SOCKS4 || WITH_RAWIP #if WITH_UNIX || HAVE_SYS_UN_H
# define _WITH_UNIX 1
#endif
#if WITH_IP4 || WITH_IP6 || WITH_SOCKS4 || WITH_RAWIP || _WITH_UNIX
# define WITH_SOCKET 1 # define WITH_SOCKET 1
#else #else
# undef WITH_SOCKET # undef WITH_SOCKET
@ -65,6 +72,14 @@
# define _WITH_SOCKET 1 # define _WITH_SOCKET 1
#endif #endif
#if WITH_TCP
# define _WITH_TCP 1
# define _WITH_IP4 1
# if WITH_IP6
# define _WITH_IP6 1
# endif
#endif
#if WITH_IP4 || WITH_TUN #if WITH_IP4 || WITH_TUN
# define _WITH_IP4 1 # define _WITH_IP4 1
#endif #endif

434
xioengine.c Normal file
View file

@ -0,0 +1,434 @@
/* $Id$ */
/* Copyright Gerhard Rieger 2007 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this is the source file of the socat transfer loop/engine */
#include "xiosysincludes.h"
#include "xioopen.h"
#include "xiosigchld.h"
/* checks if this is a connection to a child process, and if so, sees if the
child already died, leaving some data for us.
returns <0 if an error occurred;
returns 0 if no child or not yet died or died without data (sets eof);
returns >0 if child died and left data
*/
int childleftdata(xiofile_t *xfd) {
fd_set in, out, expt;
int retval;
/* have to check if a child process died before, but left read data */
if (XIO_READABLE(xfd) &&
(XIO_RDSTREAM(xfd)->howtoclose == XIOCLOSE_SIGTERM ||
XIO_RDSTREAM(xfd)->howtoclose == XIOCLOSE_SIGKILL ||
XIO_RDSTREAM(xfd)->howtoclose == XIOCLOSE_CLOSE_SIGTERM ||
XIO_RDSTREAM(xfd)->howtoclose == XIOCLOSE_CLOSE_SIGKILL) &&
XIO_RDSTREAM(xfd)->child.pid == 0) {
struct timeval time0 = { 0,0 };
FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt);
if (XIO_READABLE(xfd) && !(XIO_RDSTREAM(xfd)->eof >= 2 && !XIO_RDSTREAM(xfd)->ignoreeof)) {
FD_SET(XIO_GETRDFD(xfd), &in);
/*0 FD_SET(XIO_GETRDFD(xfd), &expt);*/
}
do {
retval = Select(FD_SETSIZE, &in, &out, &expt, &time0);
} while (retval < 0 && errno == EINTR);
if (retval < 0) {
#if HAVE_FDS_BITS
Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s",
FD_SETSIZE, in.fds_bits[0], out.fds_bits[0],
expt.fds_bits[0], strerror(errno));
#else
Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s",
FD_SETSIZE, in.__fds_bits[0], out.__fds_bits[0],
expt.__fds_bits[0], strerror(errno));
#endif
return -1;
} else if (retval == 0) {
Info("terminated child did not leave data for us");
XIO_RDSTREAM(xfd)->eof = 2;
xfd->stream.eof = 2;
/*0 closing = MAX(closing, 1);*/
}
return 1;
}
return 0;
}
void *xioengine(void *thread_arg) {
struct threadarg_struct *engine_arg = thread_arg;
_socat(engine_arg->xfd1, engine_arg->xfd2);
free(engine_arg);
return NULL/*!*/;
}
/* here we come when the sockets are opened (in the meaning of C language),
and their options are set/applied
returns -1 on error or 0 on success */
int _socat(xiofile_t *xfd1, xiofile_t *xfd2) {
xiofile_t *sock1, *sock2;
fd_set in, out, expt;
int retval;
unsigned char *buff;
ssize_t bytes1, bytes2;
int polling = 0; /* handling ignoreeof */
int wasaction = 1; /* last select was active, do NOT sleep before next */
struct timeval total_timeout; /* the actual total timeout timer */
bool mayrd1 = false; /* sock1 has read data or eof, according to select() */
bool mayrd2 = false; /* sock2 has read data or eof, according to select() */
bool maywr1 = false; /* sock1 can be written to, according to select() */
bool maywr2 = false; /* sock2 can be written to, according to select() */
sock1 = xfd1;
sock2 = xfd2;
#if WITH_FILAN
if (xioparams->debug) {
int fdi, fdo;
int msglevel, exitlevel;
msglevel = diag_get_int('D'); /* save current message level */
diag_set_int('D', E_ERROR); /* only print errors and fatals in filan */
exitlevel = diag_get_int('e'); /* save current exit level */
diag_set_int('e', E_FATAL); /* only exit on fatals */
fdi = XIO_GETRDFD(sock1);
fdo = XIO_GETWRFD(sock1);
filan_fd(fdi, stderr);
if (fdo != fdi) {
filan_fd(fdo, stderr);
}
fdi = XIO_GETRDFD(sock2);
fdo = XIO_GETWRFD(sock2);
filan_fd(fdi, stderr);
if (fdo != fdi) {
filan_fd(fdo, stderr);
}
diag_set_int('e', exitlevel); /* restore old exit level */
diag_set_int('D', msglevel); /* restore old message level */
}
#endif /* WITH_FILAN */
/* when converting nl to crnl, size might double */
buff = Malloc(2*xioparams->bufsiz+1);
if (buff == NULL) return -1;
if (xioparams->logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') {
Info("switching to syslog");
diag_set('y', xioopts.syslogfac);
xiosetopt('l', "\0");
}
total_timeout = xioparams->total_timeout;
Notice4("starting data transfer loop with FDs [%d,%d] and [%d,%d]",
XIO_GETRDFD(sock1), XIO_GETWRFD(sock1),
XIO_GETRDFD(sock2), XIO_GETWRFD(sock2));
while (XIO_RDSTREAM(sock1)->eof <= 1 ||
XIO_RDSTREAM(sock2)->eof <= 1) {
struct timeval timeout, *to = NULL;
Debug4("data loop: sock1->eof=%d, sock2->eof=%d, 1->closing=%d, 2->closing=%d",
XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock2)->eof,
sock1->stream.closing, sock2->stream.closing);
Debug3("wasaction=%d, total_to={"F_tv_sec"."F_tv_usec"}",
wasaction, total_timeout.tv_sec, total_timeout.tv_usec);
/* for ignoreeof */
if (polling) {
if (!wasaction) {
/* yes we could do it with select but I like readable trace output */
if (xioparams->pollintv.tv_sec) Sleep(xioparams->pollintv.tv_sec);
if (xioparams->pollintv.tv_usec) Usleep(xioparams->pollintv.tv_usec);
if (xioparams->total_timeout.tv_sec != 0 ||
xioparams->total_timeout.tv_usec != 0) {
if (total_timeout.tv_usec < xioparams->pollintv.tv_usec) {
total_timeout.tv_usec += 1000000;
total_timeout.tv_sec -= 1;
}
total_timeout.tv_sec -= xioparams->pollintv.tv_sec;
total_timeout.tv_usec -= xioparams->pollintv.tv_usec;
if (total_timeout.tv_sec < 0 ||
total_timeout.tv_sec == 0 && total_timeout.tv_usec < 0) {
Notice("inactivity timeout triggered");
return 0;
}
}
} else {
wasaction = 0;
}
}
if (polling) {
/* there is a ignoreeof poll timeout, use it */
timeout = xioparams->pollintv;
to = &timeout;
} else if (xioparams->total_timeout.tv_sec != 0 ||
xioparams->total_timeout.tv_usec != 0) {
/* there might occur a total inactivity timeout */
timeout = xioparams->total_timeout;
to = &timeout;
} else {
to = NULL;
}
#if 1
if (sock1->stream.closing>=1 || sock2->stream.closing>=1) {
/* first eof already occurred, start end timer */
timeout = xioparams->closwait;
to = &timeout;
}
#endif
do {
int _errno;
FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt);
childleftdata(sock1);
childleftdata(sock2);
#if 0
if (closing>=1) {
/* first eof already occurred, start end timer */
timeout = xioparams->closwait;
to = &timeout;
closing = 2;
}
#else
if (sock1->stream.closing>=1 || sock2->stream.closing>=1) {
/* first eof already occurred, start end timer */
timeout = xioparams->closwait;
to = &timeout;
if (sock1->stream.closing==1) {
sock1->stream.closing = 2;
}
if (sock2->stream.closing==1) {
sock2->stream.closing = 2;
}
}
#endif
if (XIO_READABLE(sock1) &&
!(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof)
/*0 && !xioparams->righttoleft*/) {
Debug3("*** sock1: %p [%d,%d]", sock1, XIO_GETRDFD(sock1), XIO_GETWRFD(sock1));
if (!mayrd1) {
FD_SET(XIO_GETRDFD(sock1), &in);
}
if (!maywr2) {
FD_SET(XIO_GETWRFD(sock2), &out);
}
}
if (XIO_READABLE(sock2) &&
!(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof)
/*0 && !xioparams->lefttoright*/) {
Debug3("*** sock2: %p [%d,%d]", sock2, XIO_GETRDFD(sock2), XIO_GETWRFD(sock2));
if (!mayrd2) {
FD_SET(XIO_GETRDFD(sock2), &in);
}
if (!maywr1) {
FD_SET(XIO_GETWRFD(sock1), &out);
}
}
retval = Select(FD_SETSIZE, &in, &out, &expt, to);
_errno = errno;
if (retval < 0 && errno == EINTR) {
Info1("select(): %s", strerror(errno));
}
errno = _errno;
} while (retval < 0 && errno == EINTR);
/* attention:
when an exec'd process sends data and terminates, it is unpredictable
whether the data or the sigchild arrives first.
*/
if (retval < 0) {
#if HAVE_FDS_BITS
Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s",
FD_SETSIZE, in.fds_bits[0], out.fds_bits[0],
expt.fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0,
strerror(errno));
#else
Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s",
FD_SETSIZE, in.__fds_bits[0], out.__fds_bits[0],
expt.__fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0,
strerror(errno));
#endif
return -1;
} else if (retval == 0) {
Info2("select timed out (no data within %ld.%06ld seconds)",
(sock1->stream.closing>=1||sock2->stream.closing>=1)?
xioparams->closwait.tv_sec:xioparams->total_timeout.tv_sec,
(sock1->stream.closing>=1||sock2->stream.closing>=1)?
xioparams->closwait.tv_usec:xioparams->total_timeout.tv_usec);
if (polling && !wasaction) {
/* there was a ignoreeof poll timeout, use it */
;
} else if (xioparams->total_timeout.tv_sec != 0 ||
xioparams->total_timeout.tv_usec != 0) {
/* there was a total inactivity timeout */
Notice("inactivity timeout triggered");
return 0;
}
if (sock1->stream.closing || sock2->stream.closing) {
break;
}
/* one possibility to come here is ignoreeof on some fd, but no EOF
and no data on any descriptor - this is no indication for end! */
continue;
}
/*0 Debug1("XIO_READABLE(sock1) = %d", XIO_READABLE(sock1));*/
/*0 Debug1("XIO_GETRDFD(sock1) = %d", XIO_GETRDFD(sock1));*/
if (XIO_READABLE(sock1) && XIO_GETRDFD(sock1) >= 0 &&
FD_ISSET(XIO_GETRDFD(sock1), &in)) {
mayrd1 = true;
}
/*0 Debug1("XIO_READABLE(sock2) = %d", XIO_READABLE(sock2));*/
/*0 Debug1("XIO_GETRDFD(sock2) = %d", XIO_GETRDFD(sock2));*/
/*0 Debug1("FD_ISSET(XIO_GETRDFD(sock2), &in) = %d", FD_ISSET(XIO_GETRDFD(sock2), &in));*/
if (XIO_READABLE(sock2) && XIO_GETRDFD(sock2) >= 0 &&
FD_ISSET(XIO_GETRDFD(sock2), &in)) {
mayrd2 = true;
}
/*0 Debug2("mayrd2 = %d, maywr1 = %d", mayrd2, maywr1);*/
if (XIO_GETWRFD(sock1) >= 0 && FD_ISSET(XIO_GETWRFD(sock1), &out)) {
maywr1 = true;
}
if (XIO_GETWRFD(sock2) >= 0 && FD_ISSET(XIO_GETWRFD(sock2), &out)) {
maywr2 = true;
}
if (mayrd1 && maywr2) {
mayrd1 = false;
if ((bytes1 = xiotransfer(sock1, sock2, &buff, xioparams->bufsiz, false))
< 0) {
if (errno != EAGAIN) {
/*sock2->closing = MAX(socks2->closing, 1);*/
Notice("socket 1 to socket 2 is in error");
if (/*0 xioparams->lefttoright*/ !XIO_READABLE(sock2)) {
break;
}
}
} else if (bytes1 > 0) {
maywr2 = false;
total_timeout = xioparams->total_timeout;
wasaction = 1;
/* is more data available that has already passed select()? */
mayrd1 = (xiopending(sock1) > 0);
if (XIO_RDSTREAM(sock1)->readbytes != 0 &&
XIO_RDSTREAM(sock1)->actbytes == 0) {
/* avoid idle when all readbytes already there */
mayrd1 = true;
}
} else { /* bytes1 == 0 */
if (XIO_RDSTREAM(sock1)->ignoreeof && !sock1->stream.closing) {
;
} else {
XIO_RDSTREAM(sock1)->eof = 2;
}
/* (bytes1 == 0) handled later */
}
} else {
bytes1 = -1;
}
if (mayrd2 && maywr1) {
mayrd2 = false;
if ((bytes2 = xiotransfer(sock2, sock1, &buff, xioparams->bufsiz, true))
< 0) {
if (errno != EAGAIN) {
/*sock1->closing = MAX(sock1->closing, 1);*/
Notice("socket 2 to socket 1 is in error");
if (/*0 xioparams->righttoleft*/ !XIO_READABLE(sock1)) {
break;
}
}
} else if (bytes2 > 0) {
maywr1 = false;
total_timeout = xioparams->total_timeout;
wasaction = 1;
/* is more data available that has already passed select()? */
mayrd2 = (xiopending(sock2) > 0);
if (XIO_RDSTREAM(sock2)->readbytes != 0 &&
XIO_RDSTREAM(sock2)->actbytes == 0) {
/* avoid idle when all readbytes already there */
mayrd2 = true;
}
} else { /* bytes == 0 */
if (XIO_RDSTREAM(sock2)->ignoreeof && !sock2->stream.closing) {
;
} else {
XIO_RDSTREAM(sock2)->eof = 2;
}
/* (bytes2 == 0) handled later */
}
} else {
bytes2 = -1;
}
/* NOW handle EOFs */
if (bytes1 == 0 || XIO_RDSTREAM(sock1)->eof >= 2) {
if (XIO_RDSTREAM(sock1)->ignoreeof && !sock1->stream.closing) {
Debug1("socket 1 (fd %d) is at EOF, ignoring",
XIO_RDSTREAM(sock1)->fd1); /*! */
polling = 1;
} else {
Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1));
xioshutdown(sock2, SHUT_WR);
sock2->stream.closing = MAX(sock2->stream.closing, 1);
if (/*0 xioparams->lefttoright*/ !XIO_READABLE(sock2)) {
break;
}
}
}
if (bytes2 == 0 || XIO_RDSTREAM(sock2)->eof >= 2) {
if (XIO_RDSTREAM(sock2)->ignoreeof && !sock2->stream.closing) {
Debug1("socket 2 (fd %d) is at EOF, ignoring",
XIO_RDSTREAM(sock2)->fd1);
polling = 1;
} else {
Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2));
xioshutdown(sock1, SHUT_WR);
sock1->stream.closing = MAX(sock1->stream.closing, 1);
if (/*0 xioparams->righttoleft*/ !XIO_READABLE(sock1)) {
break;
}
}
}
}
/* close everything that's still open */
xioclose(sock1);
xioclose(sock2);
return 0;
}
/* this is the callback when the child of an address died */
int socat_sigchild(struct single *file) {
Debug3("socat_sigchild().1: file->ignoreeof=%d, file->closing=%d, file->eof=%d",
file->ignoreeof, file->closing, file->eof);
if (file->ignoreeof && !file->closing) {
;
} else {
file->eof = MAX(file->eof, 1);
file->closing = 3;
}
Debug3("socat_sigchild().9: file->ignoreeof=%d, file->closing=%d, file->eof=%d",
file->ignoreeof, file->closing, file->eof);
return 0;
}

View file

@ -41,7 +41,7 @@ static const char *addressgroupnames[] = {
"TERMIOS", "RANGE", "PTY", "PARENT", "TERMIOS", "RANGE", "PTY", "PARENT",
"UNIX", "IP4", "IP6", "INTERFACE", "UNIX", "IP4", "IP6", "INTERFACE",
"UDP", "TCP", "SOCKS4", "OPENSSL", "UDP", "TCP", "SOCKS4", "OPENSSL",
"PROCESS", "APPL", "HTTP", "undef" "PROCESS", "APPL", "HTTP", "SOCKS5"
} ; } ;
@ -89,7 +89,7 @@ static int xiohelp_option(FILE *of, const struct optname *on, const char *name)
int xioopenhelp(FILE *of, int xioopenhelp(FILE *of,
int level /* 0..only addresses, 1..and options */ int level /* 0..only addresses, 1..and options */
) { ) {
const struct addrname *an; const struct xioaddrname *an;
const struct optname *on; const struct optname *on;
int i, j; int i, j;
unsigned int groups; unsigned int groups;
@ -101,32 +101,68 @@ int xioopenhelp(FILE *of,
fputs(" echo is an alias for pipe\n", of); fputs(" echo is an alias for pipe\n", of);
fputs(" fifo is an alias for pipe\n", of); fputs(" fifo is an alias for pipe\n", of);
} }
fputs(" <single-address>!!<single-address>\n", of); fputs(" <single-address>%<single-address>\n", of);
fputs(" <single-address>\n", of); fputs(" <single-address>\n", of);
fputs(" single-address:\n", of); fputs(" single-address:\n", of);
fputs(" <address-head>[,<opts>]\n", of); fputs(" <address-head>[,<opts>]\n", of);
fputs(" address-head:\n", of); fputs(" address-head:\n", of);
an = &addressnames[0]; an = &address_names[0];
i = 0; i = 0;
while (addressnames[i].name) { while (address_names[i].name) {
if (!strcmp(an->name, an->desc->defname)) { if (!strcmp(an->name, (an->desc)[0]->common_desc.defname)) {
/* it is a canonical address name */ /* it is a canonical address name */
fprintf(of, " %s", an->name); const union xioaddr_desc **ad;
if (an->desc->syntax) { ad = an->desc;
fputs(an->desc->syntax, of); } while (*ad != NULL) {
fputs("\tgroups=", of); const char *syntax;
groups = an->desc->groups; occurred = false; int pos = 0;
fprintf(of, " %s", an->name); pos += strlen(an->name);
if ((*ad)->tag == XIOADDR_ENDPOINT) {
syntax = (*ad)->endpoint_desc.syntax;
} else if ((*ad)->tag == XIOADDR_INTER) {
syntax = (*ad)->inter_desc.syntax;
} else {
syntax = NULL;
}
if (syntax) {
fputs(syntax, of); pos += strlen(syntax); }
while (pos < 36) { putc(' ', of); ++pos; }
if ((*ad)->common_desc.leftdirs & XIOBIT_RDONLY) {
putc('r', of); } else { putc(' ', of); }
if ((*ad)->common_desc.leftdirs & XIOBIT_WRONLY) {
putc('w', of); } else { putc(' ', of); }
if ((*ad)->common_desc.leftdirs & XIOBIT_RDWR) {
putc('b', of); } else { putc(' ', of); }
putc(' ', of);
if ((*ad)->tag == 1) {
while (pos < 36) { putc(' ', of); ++pos; }
if ((*ad)->inter_desc.rightdirs & XIOBIT_RDONLY) {
putc('r', of); } else { putc(' ', of); }
if ((*ad)->inter_desc.rightdirs & XIOBIT_WRONLY) {
putc('w', of); } else { putc(' ', of); }
if ((*ad)->inter_desc.rightdirs & XIOBIT_RDWR) {
putc('b', of); } else { putc(' ', of); }
} else {
fputs(" ", of);
}
pos += 7;
fputs(" groups=", of);
groups = (*ad)->common_desc.groups; occurred = false;
for (j = 0; j < 32; ++j) { for (j = 0; j < 32; ++j) {
if (groups & 1) { if (groups & 1) {
if (occurred) { fputc(',', of); } if (occurred) { fputc(',', of); }
fprintf(of, "%s", addressgroupnames[j]); fprintf(of, "%s", addressgroupnames[j]);
pos += strlen(addressgroupnames[j]);
occurred = true; occurred = true;
} }
groups >>= 1; groups >>= 1;
} }
fputc('\n', of); fputc('\n', of);
++ad;
}
} else if (level == 2) { } else if (level == 2) {
fprintf(of, " %s is an alias name for %s\n", an->name, an->desc->defname); fprintf(of, " %s is an alias name for %s\n", an->name, (an->desc)[0]->common_desc.defname);
} }
++an; ++i; ++an; ++i;
} }

View file

@ -1,24 +1,30 @@
/* $Id: xioinitialize.c,v 1.17 2006/12/28 14:21:41 gerhard Exp $ */ /* $Id: xioinitialize.c,v 1.17 2006/12/28 14:21:41 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for the initialize function */ /* this file contains the source for the initialize function */
#include "xiosysincludes.h" #include "xiosysincludes.h"
#include "xiostatic.h"
#include "xioopen.h" #include "xioopen.h"
#include "xiolockfile.h" #include "xiolockfile.h"
#include "xiosigchld.h"
#include "xio-openssl.h" /* xio_reset_fips_mode() */ #include "xio-openssl.h" /* xio_reset_fips_mode() */
static int xioinitialized; static int xioinitialized;
xiofile_t *sock[XIO_MAXSOCK]; xiofile_t *sock[XIO_MAXSOCK];
int (*xiohook_newchild)(void); /* xio calls this function from a new child int (*xiohook_newchild)(void); /* xio calls this function in every new child
process */ process */
/* call this function before calling any other xio function.
With xioflags, you have to set the features that xio can make use of.
Use XIO_MAYALL for unrestricted use. */
/* returns 0 on success or != if an error occurred */ /* returns 0 on success or != if an error occurred */
int xioinitialize(void) { int xioinitialize(int xioflags) {
int xio_flags;
if (xioinitialized) return 0; if (xioinitialized) return 0;
/* configure and .h's cannot guarantee this */ /* configure and .h's cannot guarantee this */
@ -67,7 +73,7 @@ int xioinitialize(void) {
assert(tdata.termarg.c_ospeed == tdata.speeds[OSPEED_OFFSET]); assert(tdata.termarg.c_ospeed == tdata.speeds[OSPEED_OFFSET]);
#endif #endif
} }
#endif #endif /* WITH_TERMIOS */
/* these dependencies required in applyopts() for OFUNC_FCNTL */ /* these dependencies required in applyopts() for OFUNC_FCNTL */
assert(F_GETFD == F_SETFD-1); assert(F_GETFD == F_SETFD-1);
@ -103,15 +109,41 @@ int xioinitialize(void) {
return -1; return -1;
} }
xio_flags = xioflags;
if ((xio_flags|XIO_MAYFORK) || (xio_flags|XIO_MAYCHILD) ||
(xio_flags|XIO_MAYCHAIN)) {
#if HAVE_SIGACTION
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_NOCLDSTOP|SA_RESTART|SA_SIGINFO
#ifdef SA_NOMASK
|SA_NOMASK
#endif
;
act.sa_sigaction = childdied;
if (Sigaction(SIGCHLD, &act, NULL) < 0) {
/*! Linux man does not explicitely say that errno is defined */
Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied, strerror(errno));
}
#else /* !HAVE_SIGACTION */
act.sa_handler = childdied;
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
}
#endif /* !HAVE_SIGACTION */
}
xioinitialized = 1; xioinitialized = 1;
return 0; return 0;
} }
/* well, this function is not for initialization, but I could not find a better /* well, this function is not for initialization, but I could not find a better
place for it source file for it
it is called in the child process after fork it is called in the child process after fork
it drops the locks of the xiofile's so only the parent owns them it drops the lock references of the xiofile's so only the parent owns them
*/ */
void xiodroplocks(void) { void xiodroplocks(void) {
int i; int i;
@ -124,6 +156,7 @@ void xiodroplocks(void) {
} }
#if 0
/* consider an invokation like this: /* consider an invokation like this:
socat -u exec:'some program that accepts data' tcp-l:...,fork socat -u exec:'some program that accepts data' tcp-l:...,fork
we do not want the program to be killed by the first tcp-l sub process, it's we do not want the program to be killed by the first tcp-l sub process, it's
@ -146,16 +179,17 @@ static int xio_nokill(xiofile_t *sock) {
case XIO_TAG_WRONLY: case XIO_TAG_WRONLY:
case XIO_TAG_RDWR: case XIO_TAG_RDWR:
/* here is the core of this function */ /* here is the core of this function */
switch (sock->stream.howtoend) { switch (sock->stream.howtoclose) {
case END_SHUTDOWN_KILL: sock->stream.howtoend = END_CLOSE; break; case END_SHUTDOWN_KILL: sock->stream.howtoclose = END_CLOSE; break;
case END_CLOSE_KILL: sock->stream.howtoend = END_CLOSE; break; case END_CLOSE_KILL: sock->stream.howtoclose = END_CLOSE; break;
case END_SHUTDOWN: sock->stream.howtoend = END_CLOSE; break; case END_SHUTDOWN: sock->stream.howtoclose = END_CLOSE; break;
default: break; default: break;
} }
break; break;
} }
return result; return result;
} }
#endif /* 0 */
/* call this function immediately after fork() in child process */ /* call this function immediately after fork() in child process */
/* it performs some neccessary actions /* it performs some neccessary actions
@ -175,6 +209,7 @@ int xio_forked_inchild(void) {
} }
} }
#if 0
/* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */ /* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */
if (sock1 != NULL) { if (sock1 != NULL) {
int result2; int result2;
@ -182,6 +217,7 @@ int xio_forked_inchild(void) {
if (result2 < 0) Exit(1); if (result2 < 0) Exit(1);
result |= result2; result |= result2;
} }
#endif
return result; return result;
} }

View file

@ -1,5 +1,5 @@
/* $Id: xiolayer.c,v 1.7 2005/08/18 19:56:05 gerhard Exp $ */ /* $Id: xiolayer.c,v 1.7 2005/08/18 19:56:05 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2005 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for common options */ /* this file contains the source for common options */
@ -18,8 +18,8 @@ const struct optdesc opt_lockfile = { "lockfile", NULL, OPT_LOCKFILE, GROUP_A
const struct optdesc opt_waitlock = { "waitlock", NULL, OPT_WAITLOCK, GROUP_APPL, PH_INIT, TYPE_FILENAME, OFUNC_EXT, 0, 0 }; const struct optdesc opt_waitlock = { "waitlock", NULL, OPT_WAITLOCK, GROUP_APPL, PH_INIT, TYPE_FILENAME, OFUNC_EXT, 0, 0 };
/****** APPL addresses ******/ /****** APPL addresses ******/
#if WITH_RETRY #if WITH_RETRY
const struct optdesc opt_forever = { "forever", NULL, OPT_FOREVER, GROUP_RETRY, PH_INIT, TYPE_BOOL, OFUNC_EXT, (int)(&((struct single *)0)->forever), sizeof(((struct single *)0)->forever) }; const struct optdesc opt_forever = { "forever", NULL, OPT_FOREVER, GROUP_RETRY, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (int)(&((struct single *)0)->forever), sizeof(((struct single *)0)->forever) };
const struct optdesc opt_intervall = { "intervall", NULL, OPT_INTERVALL, GROUP_RETRY, PH_INIT, TYPE_TIMESPEC, OFUNC_EXT, (int)(&((struct single *)0)->intervall), sizeof(((struct single *)0)->intervall) }; const struct optdesc opt_intervall = { "intervall", NULL, OPT_INTERVALL, GROUP_RETRY, PH_INIT, TYPE_TIMESPEC, OFUNC_OFFSET, (int)(&((struct single *)0)->intervall), sizeof(((struct single *)0)->intervall) };
const struct optdesc opt_retry = { "retry", NULL, OPT_RETRY, GROUP_RETRY, PH_INIT, TYPE_UINT, OFUNC_EXT, (int)(&((struct single *)0)->retry), sizeof(((struct single *)0)->retry) }; const struct optdesc opt_retry = { "retry", NULL, OPT_RETRY, GROUP_RETRY, PH_INIT, TYPE_UINT, OFUNC_OFFSET, (int)(&((struct single *)0)->retry), sizeof(((struct single *)0)->retry) };
#endif #endif

View file

@ -29,6 +29,7 @@
#include "xio-tcp.h" #include "xio-tcp.h"
#include "xio-udp.h" #include "xio-udp.h"
#include "xio-socks.h" #include "xio-socks.h"
#include "xio-socks5.h"
#include "xio-proxy.h" #include "xio-proxy.h"
#endif /* WITH_SOCKET */ #endif /* WITH_SOCKET */
#include "xio-progcall.h" #include "xio-progcall.h"
@ -41,5 +42,7 @@
#include "xio-tcpwrap.h" #include "xio-tcpwrap.h"
#include "xio-ext2.h" #include "xio-ext2.h"
#include "xio-tun.h" #include "xio-tun.h"
#include "xio-nop.h"
#include "xio-test.h"
#endif /* !defined(__xiomodes_h_included) */ #endif /* !defined(__xiomodes_h_included) */

1016
xioopen.c

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* $Id: xioopen.h,v 1.22 2006/05/12 20:14:05 gerhard Exp $ */ /* $Id: xioopen.h,v 1.22.2.1 2006/07/24 19:26:29 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xioopen_h_included #ifndef __xioopen_h_included
@ -33,16 +33,25 @@ extern const struct optdesc opt_tabdly;
extern const struct optdesc opt_csize; extern const struct optdesc opt_csize;
struct addrname { struct xioaddrname {
const char *name; const char *name;
const struct addrdesc *desc; const union xioaddr_desc **desc;
} ;
struct xioaddr_endpoint_name {
const char *name;
const struct xioaddr_endpoint_desc **desc;
} ; } ;
extern const char *ddirection[]; extern const char *ddirection[];
extern const char *filetypenames[]; extern const char *filetypenames[];
extern const struct addrname addressnames[]; extern const struct xioaddrname address_names[];
extern const struct optname optionnames[]; extern const struct optname optionnames[];
extern xiofile_t *socat_open(const char *addrs0, int dirs, int flags);
extern xiofile_t *xioparse_dual(const char **addr);
extern int xioopen_inter_dual(xiofile_t *xfd, int xioflags);
extern int xioopen_endpoint_dual(xiofile_t *xfd, int xioflags);
extern int xioopen_makedual(xiofile_t *file); extern int xioopen_makedual(xiofile_t *file);
#define retropt_2bytes(o,c,r) retropt_ushort(o,c,r) #define retropt_2bytes(o,c,r) retropt_ushort(o,c,r)

View file

@ -88,6 +88,12 @@ bool xioopts_ignoregroups;
# define IF_SOCKS4(a,b) # define IF_SOCKS4(a,b)
#endif #endif
#if WITH_SOCKS5
# define IF_SOCKS5(a,b) {a,b},
#else
# define IF_SOCKS5(a,b)
#endif
#if WITH_PROXY #if WITH_PROXY
# define IF_PROXY(a,b) {a,b}, # define IF_PROXY(a,b) {a,b},
#else #else
@ -1190,6 +1196,7 @@ const struct optname optionnames[] = {
#endif #endif
IF_ANY ("setuid", &opt_setuid) IF_ANY ("setuid", &opt_setuid)
IF_ANY ("setuid-early", &opt_setuid_early) IF_ANY ("setuid-early", &opt_setuid_early)
IF_ANY ("shut-none", &opt_shut_none)
#if WITH_EXEC || WITH_SYSTEM #if WITH_EXEC || WITH_SYSTEM
IF_ANY ("sid", &opt_setsid) IF_ANY ("sid", &opt_setsid)
#endif #endif
@ -1302,6 +1309,8 @@ const struct optname optionnames[] = {
#ifdef SO_USELOOPBACK /* AIX433, Solaris */ #ifdef SO_USELOOPBACK /* AIX433, Solaris */
IF_SOCKET ("so-useloopback", &opt_so_useloopback) IF_SOCKET ("so-useloopback", &opt_so_useloopback)
#endif /* SO_USELOOPBACK */ #endif /* SO_USELOOPBACK */
IF_SOCKS5 ("socks5-password", &opt_socks5_password)
IF_SOCKS5 ("socks5-username", &opt_socks5_username)
IF_SOCKS4 ("socksport", &opt_socksport) IF_SOCKS4 ("socksport", &opt_socksport)
IF_SOCKS4 ("socksuser", &opt_socksuser) IF_SOCKS4 ("socksuser", &opt_socksuser)
IF_IPAPP ("sourceport", &opt_sourceport) IF_IPAPP ("sourceport", &opt_sourceport)
@ -1560,9 +1569,9 @@ const struct optname optionnames[] = {
to the array opts. Uses the option table 'optionnames'. to the array opts. Uses the option table 'optionnames'.
returns 0 on success, -1 on error, 1 on unknown/wrong option returns 0 on success, -1 on error, 1 on unknown/wrong option
*/ */
int parseopts(const char **a, unsigned int groups, struct opt **opts) { int parseopts(const char **a, struct opt **opts) {
return parseopts_table(a, groups, opts, optionnames, return parseopts_table(a, opts, optionnames,
sizeof(optionnames)/sizeof(struct optname)-1); sizeof(optionnames)/sizeof(struct optname)-1);
} }
@ -1571,7 +1580,7 @@ int parseopts(const char **a, unsigned int groups, struct opt **opts) {
to the array opts. Uses the specified option table. to the array opts. Uses the specified option table.
returns 0 on success, -1 on error, 1 on unknown/wrong option returns 0 on success, -1 on error, 1 on unknown/wrong option
*/ */
int parseopts_table(const char **a, unsigned int groups, struct opt **opts, int parseopts_table(const char **a, struct opt **opts,
const struct optname optionnames[], size_t optionnum) { const struct optname optionnames[], size_t optionnum) {
int i=0; int i=0;
struct opt *opt; struct opt *opt;
@ -1603,15 +1612,15 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
} ; } ;
i = 0; i = 0;
/*endkey[i++] = xioopts.chainsep;*/ /* default: "|" */ endkey[i++] = xioopts.chainsep; /* default: "|" */
endkey[i++] = xioopts.pipesep; /* default: "!!" */ endkey[i++] = xioopts.pipesep; /* default: "%" */
endkey[i++] = ","/*xioopts.comma*/; /* default: "," */ endkey[i++] = ","/*xioopts.comma*/; /* default: "," */
endkey[i++] = "="; endkey[i++] = "=";
endkey[i++] = NULL; endkey[i++] = NULL;
i = 0; i = 0;
/*endval[i++] = xioopts.chainsep;*/ /* default: "|" */ endval[i++] = xioopts.chainsep; /* default: "|" */
endval[i++] = xioopts.pipesep; /* default: "!!" */ endval[i++] = xioopts.pipesep; /* default: "%" */
endval[i++] = ","/*xioopts.comma*/; /* default: "," */ endval[i++] = ","/*xioopts.comma*/; /* default: "," */
endval[i++] = NULL; endval[i++] = NULL;
@ -1637,7 +1646,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
len = sizeof(token); tokp = token; len = sizeof(token); tokp = token;
parsres = parsres =
nestlex(a, &tokp, &len, endkey, hquotes, squotes, nests, nestlex(a, &tokp, &len, endkey, hquotes, squotes, nests,
true, true, false); true, true, true, false);
if (parsres != 0) { if (parsres != 0) {
return -1; return -1;
} }
@ -1654,6 +1663,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
continue; continue;
} }
#if 0
if (!(ent->desc->group & groups) && !(ent->desc->group & GROUP_ANY) && if (!(ent->desc->group & groups) && !(ent->desc->group & GROUP_ANY) &&
!xioopts_ignoregroups) { !xioopts_ignoregroups) {
Error1("parseopts(): option \"%s\" not supported with this address type", Error1("parseopts(): option \"%s\" not supported with this address type",
@ -1664,6 +1674,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
continue; continue;
#endif #endif
} }
#endif
(*opts)[i].desc = ent->desc; (*opts)[i].desc = ent->desc;
if (!strncmp(*a, assign_str, strlen(assign_str))) { if (!strncmp(*a, assign_str, strlen(assign_str))) {
@ -1672,7 +1683,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
len = sizeof(token); tokp = token; len = sizeof(token); tokp = token;
parsres = parsres =
nestlex(a, &tokp, &len, endval, hquotes, squotes, nests, nestlex(a, &tokp, &len, endval, hquotes, squotes, nests,
true, true, false); true, true, true, false);
if (parsres != 0) { if (parsres != 0) {
return -1; return -1;
} }
@ -1981,7 +1992,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
/*! result= */ /*! result= */
nestlex((const char **)&tokp, &buffp, &bufspc, nestlex((const char **)&tokp, &buffp, &bufspc,
ends, NULL, NULL, nests, ends, NULL, NULL, nests,
true, false, false); true, true, false, false);
if (*tokp != ':') { if (*tokp != ':') {
Error1("syntax in option %s: missing ':'", token); Error1("syntax in option %s: missing ':'", token);
} }
@ -1994,7 +2005,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
/*! result= */ /*! result= */
nestlex((const char **)&tokp, &buffp, &bufspc, nestlex((const char **)&tokp, &buffp, &bufspc,
ends, NULL, NULL, nests, ends, NULL, NULL, nests,
true, false, false); true, true, false, false);
*buffp++ = '\0'; *buffp++ = '\0';
(*opts)[i].value.u_ip_mreq.param2 = strdup(buff); /*!!! NULL */ (*opts)[i].value.u_ip_mreq.param2 = strdup(buff); /*!!! NULL */
@ -2034,7 +2045,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
tokp = token; tokp = token;
nestlex((const char **)&tokp, &buffp, &bufspc, nestlex((const char **)&tokp, &buffp, &bufspc,
ends, NULL, NULL, nests, ends, NULL, NULL, nests,
true, false, false); true, true, false, false);
if (*tokp != '\0') { if (*tokp != '\0') {
Error1("trailing data in option \"%s\"", token); Error1("trailing data in option \"%s\"", token);
} }
@ -2069,6 +2080,32 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
return 0; return 0;
} }
/* checks if the options conform to the group set.
returns 0 if all options conform to the group set,
or -1 otherwise. */
int xiocheckopts(struct opt *opts, unsigned int groups) {
const struct opt *opt = opts;
if (opts == NULL) {
return 0;
}
while (opt->desc != ODESC_END) {
if (!(opt->desc->group & groups) &&
!(opt->desc->group & GROUP_ANY) &&
!xioopts_ignoregroups) {
Error1("option \"%s\" not supported with this address type",
opt->desc->defname);
Info2("parseopts() groups=%08x, opt->group=%08x",
groups, opt->desc->group);
return -1;
}
}
return 0;
}
/* copy the already parsed options for repeated application, but only those /* copy the already parsed options for repeated application, but only those
matching groups ANY and <groups> */ matching groups ANY and <groups> */
struct opt *copyopts(const struct opt *opts, unsigned int groups) { struct opt *copyopts(const struct opt *opts, unsigned int groups) {
@ -2479,7 +2516,7 @@ int retropt_bind(struct opt *opts,
portallowed = (feats>=2); portallowed = (feats>=2);
bindp = bindname; bindp = bindname;
nestlex((const char **)&bindp, &hostp, &hostlen, ends, NULL, NULL, nests, nestlex((const char **)&bindp, &hostp, &hostlen, ends, NULL, NULL, nests,
true, false, false); true, true, false, false);
*hostp++ = '\0'; *hostp++ = '\0';
if (!strncmp(bindp, portsep, strlen(portsep))) { if (!strncmp(bindp, portsep, strlen(portsep))) {
if (!portallowed) { if (!portallowed) {
@ -2591,7 +2628,8 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) {
long mask = opt->desc->arg3; long mask = opt->desc->arg3;
if (Ioctl(fd, getreq, (void *)&val) < 0) { if (Ioctl(fd, getreq, (void *)&val) < 0) {
Error4("ioctl(%d, 0x%x, %p): %s", Error5("option \"%s\": ioctl(%d, 0x%x, %p): %s",
opt->desc->defname,
fd, opt->desc->major, (void *)&val, strerror(errno)); fd, opt->desc->major, (void *)&val, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue; opt->desc = ODESC_ERROR; ++opt; continue;
} }
@ -3339,6 +3377,8 @@ static int applyopt_offset(struct single *xfd, struct opt *opt) {
switch (opt->desc->type) { switch (opt->desc->type) {
case TYPE_BOOL: case TYPE_BOOL:
*(bool *)ptr = opt->value.u_bool; break; *(bool *)ptr = opt->value.u_bool; break;
case TYPE_UINT:
*(unsigned int *)ptr = opt->value.u_uint; break;
case TYPE_DOUBLE: case TYPE_DOUBLE:
*(double *)ptr = opt->value.u_double; break; *(double *)ptr = opt->value.u_double; break;
case TYPE_TIMEVAL: case TYPE_TIMEVAL:
@ -3358,6 +3398,8 @@ static int applyopt_offset(struct single *xfd, struct opt *opt) {
case TYPE_CONST: case TYPE_CONST:
*(int *)ptr = opt->desc->minor; *(int *)ptr = opt->desc->minor;
break; break;
case TYPE_TIMESPEC:
*(struct timespec *)ptr = opt->value.u_timespec; break;
default: default:
Error1("applyopt_offset(): type %d not implemented", Error1("applyopt_offset(): type %d not implemented",
opt->desc->type); opt->desc->type);
@ -3574,10 +3616,10 @@ mc:addr
#endif #endif
#if HAVE_STRUCT_IP_MREQN #if HAVE_STRUCT_IP_MREQN
if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor, if (Setsockopt(xfd->fd1, opt->desc->major, opt->desc->minor,
&ip4_mreqn.mreqn, sizeof(ip4_mreqn.mreqn)) < 0) { &ip4_mreqn.mreqn, sizeof(ip4_mreqn.mreqn)) < 0) {
Error8("setsockopt(%d, %d, %d, {0x%08x,0x%08x,%d}, "F_Zu"): %s", Error8("setsockopt(%d, %d, %d, {0x%08x,0x%08x,%d}, "F_Zu"): %s",
xfd->fd, opt->desc->major, opt->desc->minor, xfd->fd1, opt->desc->major, opt->desc->minor,
ip4_mreqn.mreqn.imr_multiaddr.s_addr, ip4_mreqn.mreqn.imr_multiaddr.s_addr,
ip4_mreqn.mreqn.imr_address.s_addr, ip4_mreqn.mreqn.imr_address.s_addr,
ip4_mreqn.mreqn.imr_ifindex, ip4_mreqn.mreqn.imr_ifindex,
@ -3586,10 +3628,10 @@ mc:addr
opt->desc = ODESC_ERROR; continue; opt->desc = ODESC_ERROR; continue;
} }
#else #else
if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor, if (Setsockopt(xfd->fd1, opt->desc->major, opt->desc->minor,
&ip4_mreqn.mreq, sizeof(ip4_mreqn.mreq)) < 0) { &ip4_mreqn.mreq, sizeof(ip4_mreqn.mreq)) < 0) {
Error7("setsockopt(%d, %d, %d, {0x%08x,0x%08x}, "F_Zu"): %s", Error7("setsockopt(%d, %d, %d, {0x%08x,0x%08x}, "F_Zu"): %s",
xfd->fd, opt->desc->major, opt->desc->minor, xfd->fd1, opt->desc->major, opt->desc->minor,
ip4_mreqn.mreq.imr_multiaddr, ip4_mreqn.mreq.imr_multiaddr,
ip4_mreqn.mreq.imr_interface, ip4_mreqn.mreq.imr_interface,
sizeof(ip4_mreqn.mreq), sizeof(ip4_mreqn.mreq),
@ -3626,10 +3668,10 @@ mc:addr
ip6_mreq.ipv6mr_interface = htonl(0); ip6_mreq.ipv6mr_interface = htonl(0);
} }
if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor, if (Setsockopt(xfd->fd1, opt->desc->major, opt->desc->minor,
&ip6_mreq, sizeof(ip6_mreq)) < 0) { &ip6_mreq, sizeof(ip6_mreq)) < 0) {
Error6("setsockopt(%d, %d, %d, {...,0x%08x}, "F_Zu"): %s", Error6("setsockopt(%d, %d, %d, {...,0x%08x}, "F_Zu"): %s",
xfd->fd, opt->desc->major, opt->desc->minor, xfd->fd1, opt->desc->major, opt->desc->minor,
ip6_mreq.ipv6mr_interface, ip6_mreq.ipv6mr_interface,
sizeof(ip6_mreq), sizeof(ip6_mreq),
strerror(errno)); strerror(errno));
@ -3668,7 +3710,7 @@ int applyopts_signal(struct single *xfd, struct opt *opts) {
++opt; continue; ++opt; continue;
} }
if (xio_opt_signal(xfd->para.exec.pid, opt->desc->major) < 0) { if (xio_opt_signal(xfd->child.pid, opt->desc->major) < 0) {
opt->desc = ODESC_ERROR; continue; opt->desc = ODESC_ERROR; continue;
} }
opt->desc = ODESC_DONE; opt->desc = ODESC_DONE;
@ -3685,15 +3727,23 @@ int _xio_openlate(struct single *fd, struct opt *opts) {
_xioopen_setdelayeduser(); _xioopen_setdelayeduser();
if ((result = applyopts(fd->fd, opts, PH_LATE)) < 0) { if ((result = applyopts(fd->fd1, opts, PH_LATE)) < 0) {
return result; return result;
} }
#if 0 /*! need to copy opts before previous statement! */
if (fd->fdtype == FDTYPE_DOUBLE) {
if ((result = applyopts(fd->fd2, opts, PH_LATE)) < 0) {
return result;
}
}
#endif
if ((result = applyopts_single(fd, opts, PH_LATE)) < 0) { if ((result = applyopts_single(fd, opts, PH_LATE)) < 0) {
return result; return result;
} }
if ((result = applyopts(fd->fd, opts, PH_LATE2)) < 0) { if ((result = applyopts(fd->fd1, opts, PH_LATE2)) < 0) {
return result; return result;
} }
/*! need to apply to fd2 too! */
if ((numleft = leftopts(opts)) > 0) { if ((numleft = leftopts(opts)) > 0) {
showleft(opts); showleft(opts);

View file

@ -145,6 +145,7 @@ enum e_func {
#define GROUP_PROCESS 0x10000000 /* a process related option */ #define GROUP_PROCESS 0x10000000 /* a process related option */
#define GROUP_APPL 0x20000000 /* option handled by data loop */ #define GROUP_APPL 0x20000000 /* option handled by data loop */
#define GROUP_HTTP 0x40000000 /* any HTTP client */ #define GROUP_HTTP 0x40000000 /* any HTTP client */
#define GROUP_SOCKS5 0x80000000
#define GROUP_ANY (GROUP_PROCESS|GROUP_APPL) #define GROUP_ANY (GROUP_PROCESS|GROUP_APPL)
#define GROUP_ALL 0xffffffff #define GROUP_ALL 0xffffffff
@ -533,6 +534,7 @@ enum e_optcode {
OPT_SETSID, OPT_SETSID,
OPT_SETUID, OPT_SETUID,
OPT_SETUID_EARLY, OPT_SETUID_EARLY,
OPT_SHUT_NONE,
OPT_SIGHUP, OPT_SIGHUP,
OPT_SIGINT, OPT_SIGINT,
OPT_SIGQUIT, OPT_SIGQUIT,
@ -630,6 +632,8 @@ enum e_optcode {
#ifdef SO_USE_IFBUFS #ifdef SO_USE_IFBUFS
OPT_SO_USE_IFBUFS, OPT_SO_USE_IFBUFS,
#endif /* SO_USE_IFBUFS */ #endif /* SO_USE_IFBUFS */
OPT_SOCKS5_PASSWORD,
OPT_SOCKS5_USERNAME,
#if 1 || defined(WITH_SOCKS4) #if 1 || defined(WITH_SOCKS4)
OPT_SOCKSPORT, OPT_SOCKSPORT,
OPT_SOCKSUSER, OPT_SOCKSUSER,
@ -856,10 +860,10 @@ extern int applyopts_single(struct single *fd, struct opt *opts, enum e_phase ph
extern int applyopts_offset(struct single *xfd, struct opt *opts); extern int applyopts_offset(struct single *xfd, struct opt *opts);
extern int applyopts_signal(struct single *xfd, struct opt *opts); extern int applyopts_signal(struct single *xfd, struct opt *opts);
extern int _xio_openlate(struct single *fd, struct opt *opts); extern int _xio_openlate(struct single *fd, struct opt *opts);
extern int parseopts(const char **a, unsigned int groups, struct opt **opts); extern int parseopts(const char **a, struct opt **opts);
extern int parseopts_table(const char **a, unsigned int groups, extern int parseopts_table(const char **a, struct opt **opts,
struct opt **opts,
const struct optname optionnames[], size_t optionnum); const struct optname optionnames[], size_t optionnum);
extern int xiocheckopts(struct opt *opts, unsigned int groups);
extern struct opt *copyopts(const struct opt *opts, unsigned int groups); extern struct opt *copyopts(const struct opt *opts, unsigned int groups);
extern struct opt *moveopts(struct opt *opts, unsigned int groups); extern struct opt *moveopts(struct opt *opts, unsigned int groups);
extern int leftopts(const struct opt *opts); extern int leftopts(const struct opt *opts);

View file

@ -1,5 +1,5 @@
/* $Id: xioparam.c,v 1.10 2006/06/19 20:30:24 gerhard Exp $ */ /* $Id: xioparam.c,v 1.10 2006/06/19 20:30:24 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for xio options handling */ /* this file contains the source for xio options handling */
@ -12,16 +12,28 @@
/* options that can be applied to this module */ /* options that can be applied to this module */
xioopts_t xioopts = { xioopts_t xioopts = {
false, /* strictopts */ false, /* strictopts */
"!!", /* pipesep */ "%", /* pipesep */
":", /* paramsep */ ":", /* paramsep */
",", /* optionsep */ ",", /* optionsep */
':', /* ip4portsep */ ':', /* ip4portsep */
':', /* ip6portsep */ ':', /* ip6portsep */
'\0', /* logopt */
NULL, /* syslogfac */ NULL, /* syslogfac */
'4', /* default_ip */ '4', /* default_ip */
'4' /* preferred_ip */ '4', /* preferred_ip */
"^", /* reversechar */
"|", /* chainsep */
8192, /* bufsiz */
false, /* verbose */
false, /* verbhex */
0, /* debug */
's', /* logopt */
{0,0}, /* total_timeout */
{1,0}, /* pollintv */
{0,500000}, /* closwait */
false, /* lefttoright */
false, /* righttoleft */
} ; } ;
xioopts_t *xioparams = &xioopts;
/* allow application to set xioopen options */ /* allow application to set xioopen options */

View file

@ -9,6 +9,7 @@
#include "xio-termios.h" #include "xio-termios.h"
#include "xio-socket.h" #include "xio-socket.h"
#include "xio-test.h"
#include "xio-readline.h" #include "xio-readline.h"
#include "xio-openssl.h" #include "xio-openssl.h"
@ -21,6 +22,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
int nexthead; int nexthead;
#endif #endif
struct single *pipe; struct single *pipe;
int fd;
int _errno; int _errno;
if (file->tag == XIO_TAG_INVALID) { if (file->tag == XIO_TAG_INVALID) {
@ -50,10 +52,12 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
} }
} }
fd = XIO_GETRDFD(file);
switch (pipe->dtype & XIODATA_READMASK) { switch (pipe->dtype & XIODATA_READMASK) {
case XIOREAD_STREAM: case XIOREAD_STREAM:
do { do {
bytes = Read(pipe->fd, buff, bufsiz); bytes = Read(fd, buff, bufsiz);
} while (bytes < 0 && errno == EINTR); } while (bytes < 0 && errno == EINTR);
if (bytes < 0) { if (bytes < 0) {
_errno = errno; _errno = errno;
@ -61,12 +65,30 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
#if 1 #if 1
case EPIPE: case ECONNRESET: case EPIPE: case ECONNRESET:
Warn4("read(%d, %p, "F_Zu"): %s", Warn4("read(%d, %p, "F_Zu"): %s",
pipe->fd, buff, bufsiz, strerror(_errno)); fd, buff, bufsiz, strerror(_errno));
break; break;
#endif #endif
default: default:
Error4("read(%d, %p, "F_Zu"): %s", Error4("read(%d, %p, "F_Zu"): %s",
pipe->fd, buff, bufsiz, strerror(_errno)); fd, buff, bufsiz, strerror(_errno));
}
return -1;
}
break;
case XIODATA_PTY:
do {
bytes = Read(fd, buff, bufsiz);
} while (bytes < 0 && errno == EINTR);
if (bytes < 0) {
_errno = errno;
if (_errno == EIO) {
Notice4("read(%d, %p, "F_Zu"): %s (probably PTY closed)",
fd, buff, bufsiz, strerror(_errno));
return 0;
} else {
Error4("read(%d, %p, "F_Zu"): %s",
fd, buff, bufsiz, strerror(_errno));
} }
errno = _errno; errno = _errno;
return -1; return -1;
@ -75,17 +97,17 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
case XIOREAD_PTY: case XIOREAD_PTY:
do { do {
bytes = Read(pipe->fd, buff, bufsiz); bytes = Read(fd, buff, bufsiz);
} while (bytes < 0 && errno == EINTR); } while (bytes < 0 && errno == EINTR);
if (bytes < 0) { if (bytes < 0) {
_errno = errno; _errno = errno;
if (_errno == EIO) { if (_errno == EIO) {
Notice4("read(%d, %p, "F_Zu"): %s (probably PTY closed)", Notice4("read(%d, %p, "F_Zu"): %s (probably PTY closed)",
pipe->fd, buff, bufsiz, strerror(_errno)); fd, buff, bufsiz, strerror(_errno));
return 0; return 0;
} else { } else {
Error4("read(%d, %p, "F_Zu"): %s", Error4("read(%d, %p, "F_Zu"): %s",
pipe->fd, buff, bufsiz, strerror(_errno)); fd, buff, bufsiz, strerror(_errno));
} }
errno = _errno; errno = _errno;
return -1; return -1;
@ -100,6 +122,15 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
break; break;
#endif /* WITH_READLINE */ #endif /* WITH_READLINE */
#if WITH_TEST
case XIOREAD_TEST:
/* this function prints its error messages */
if ((bytes = xioread_test(pipe, buff, bufsiz)) < 0) {
return -1;
}
break;
#endif /* WITH_TEST */
#if WITH_OPENSSL #if WITH_OPENSSL
case XIOREAD_OPENSSL: case XIOREAD_OPENSSL:
/* this function prints its error messages */ /* this function prints its error messages */
@ -118,14 +149,13 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
char infobuff[256]; char infobuff[256];
do { do {
bytes = bytes = Recvfrom(fd, buff, bufsiz, 0, &from.soa, &fromlen);
Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen);
} while (bytes < 0 && errno == EINTR); } while (bytes < 0 && errno == EINTR);
if (bytes < 0) { if (bytes < 0) {
char infobuff[256]; char infobuff[256];
_errno = errno; _errno = errno;
Error6("recvfrom(%d, %p, "F_Zu", 0, %s, {"F_socklen"}): %s", Error6("recvfrom(%d, %p, "F_Zu", 0, %s, {"F_socklen"}): %s",
pipe->fd, buff, bufsiz, fd, buff, bufsiz,
sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)), sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)),
fromlen, strerror(errno)); fromlen, strerror(errno));
errno = _errno; errno = _errno;
@ -209,7 +239,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
headlen = 4*((struct ip *)buff)->ip_vhl; headlen = 4*((struct ip *)buff)->ip_vhl;
#endif #endif
if (headlen > bytes) { if (headlen > bytes) {
Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd); Warn1("xioread(%d, ...)/IP4: short packet", fd);
bytes = 0; bytes = 0;
} else { } else {
memmove(buff, ((char *)buff)+headlen, bytes-headlen); memmove(buff, ((char *)buff)+headlen, bytes-headlen);
@ -286,11 +316,11 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
socket_init(pipe->para.socket.la.soa.sa_family, &from); socket_init(pipe->para.socket.la.soa.sa_family, &from);
/* get source address */ /* get source address */
if (xiogetpacketsrc(pipe->fd, &from, &fromlen) < 0) { if (xiogetpacketsrc(fd, &from, &fromlen) < 0) {
return STAT_RETRYNOW; return STAT_RETRYNOW;
} }
if (xiocheckpeer(pipe, &from, &pipe->para.socket.la) < 0) { if (xiocheckpeer(pipe, &from, &pipe->para.socket.la) < 0) {
Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); /* drop */ Recvfrom(fd, buff, bufsiz, 0, &from.soa, &fromlen); /* drop */
errno = EAGAIN; return -1; errno = EAGAIN; return -1;
} }
Info1("permitting packet from %s", Info1("permitting packet from %s",
@ -299,13 +329,13 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
do { do {
bytes = bytes =
Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); Recvfrom(fd, buff, bufsiz, 0, &from.soa, &fromlen);
} while (bytes < 0 && errno == EINTR); } while (bytes < 0 && errno == EINTR);
if (bytes < 0) { if (bytes < 0) {
char infobuff[256]; char infobuff[256];
_errno = errno; _errno = errno;
Error6("recvfrom(%d, %p, "F_Zu", 0, %s, "F_socklen"): %s", Error6("recvfrom(%d, %p, "F_Zu", 0, %s, "F_socklen"): %s",
pipe->fd, buff, bufsiz, fd, buff, bufsiz,
sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)), sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)),
fromlen, strerror(errno)); fromlen, strerror(errno));
errno = _errno; errno = _errno;
@ -334,7 +364,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
headlen = 4*((struct ip *)buff)->ip_vhl; headlen = 4*((struct ip *)buff)->ip_vhl;
#endif #endif
if (headlen > bytes) { if (headlen > bytes) {
Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd); Warn1("xioread(%d, ...)/IP4: short packet", fd);
bytes = 0; bytes = 0;
} else { } else {
memmove(buff, ((char *)buff)+headlen, bytes-headlen); memmove(buff, ((char *)buff)+headlen, bytes-headlen);

View file

@ -8,6 +8,9 @@
#include "xiosysincludes.h" #include "xiosysincludes.h"
#include "xioopen.h" #include "xioopen.h"
static int xioshut_sleep_kill(pid_t sub, unsigned long usec, int sig);
static pid_t socat_kill_pid; /* here we pass the pid to be killed in sighandler */ static pid_t socat_kill_pid; /* here we pass the pid to be killed in sighandler */
static void signal_kill_pid(int dummy) { static void signal_kill_pid(int dummy) {
@ -15,15 +18,21 @@ static void signal_kill_pid(int dummy) {
Kill(socat_kill_pid, SIGTERM); Kill(socat_kill_pid, SIGTERM);
} }
/* how: SHUT_RD, SHUT_WR, or SHUT_RDWR */
int xioshutdown(xiofile_t *sock, int how) { int xioshutdown(xiofile_t *sock, int how) {
int result = 0; int result = 0;
Debug2("xioshutdown(%p, %d)", sock, how);
Debug2("xioshutdown(): dtype=0x%x, howtoshut=0x%04x",
sock->stream.dtype, sock->stream.howtoshut);
if (sock->tag == XIO_TAG_INVALID) { if (sock->tag == XIO_TAG_INVALID) {
Error("xioshutdown(): invalid file descriptor"); Error("xioshutdown(): invalid file descriptor");
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
/*Debug3("xioshutdown: flags=%d, dtype=%d, howtoclose=%d", sock->stream.flags, sock->stream.dtype, sock->stream.howtoclose);*/
if (sock->tag == XIO_TAG_DUAL) { if (sock->tag == XIO_TAG_DUAL) {
if ((how+1)&1) { if ((how+1)&1) {
result = xioshutdown((xiofile_t *)sock->dual.stream[0], 0); result = xioshutdown((xiofile_t *)sock->dual.stream[0], 0);
@ -31,104 +40,182 @@ int xioshutdown(xiofile_t *sock, int how) {
if ((how+1)&2) { if ((how+1)&2) {
result |= xioshutdown((xiofile_t *)sock->dual.stream[1], 1); result |= xioshutdown((xiofile_t *)sock->dual.stream[1], 1);
} }
#if WITH_OPENSSL
} else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_OPENSSL) {
sycSSL_shutdown (sock->stream.para.openssl.ssl);
/*! what about half/full close? */
#endif /* WITH_OPENSSL */
} else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_PIPE) {
if ((how+1)&1) {
if (Close(sock->stream.fd) < 0) {
Info2("close(%d): %s",
sock->stream.fd, strerror(errno));
}
}
if ((how+1)&2) {
if (Close(sock->stream.para.bipipe.fdout) < 0) {
Info2("close(%d): %s",
sock->stream.para.bipipe.fdout, strerror(errno));
}
}
} else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_2PIPE) {
if ((how+1)&1) {
if (Close(sock->stream.fd) < 0) {
Info2("close(%d): %s",
sock->stream.fd, strerror(errno));
}
}
if ((how+1)&2) {
if (Close(sock->stream.para.exec.fdout) < 0) {
Info2("close(%d): %s",
sock->stream.para.exec.fdout, strerror(errno));
}
}
#if WITH_SOCKET
} else if (sock->stream.howtoend == END_SHUTDOWN) {
if ((result = Shutdown(sock->stream.fd, how)) < 0) {
Info3("shutdown(%d, %d): %s",
sock->stream.fd, how, strerror(errno));
}
} else if (sock->stream.howtoend == END_SHUTDOWN_KILL) {
if ((result = Shutdown(sock->stream.fd, how)) < 0) {
Info3("shutdown(%d, %d): %s",
sock->stream.fd, how, strerror(errno));
}
if ((sock->stream.flags&XIO_ACCMODE) == XIO_WRONLY) {
/* the child process might want to flush some data before terminating
*/
int status = 0;
/* we wait for the child process to die, but to prevent timeout
we raise an alarm after some time.
NOTE: the alarm does not terminate waitpid() on Linux/glibc (BUG?),
therefore we have to do the kill in the signal handler */
Signal(SIGALRM, signal_kill_pid);
socat_kill_pid = sock->stream.para.exec.pid;
#if HAVE_SETITIMER
/*! with next feature release, we get usec resolution and an option */
#else
Alarm(1 /*! sock->stream.para.exec.waitdie */);
#endif /* !HAVE_SETITIMER */
if (Waitpid(sock->stream.para.exec.pid, &status, 0) < 0) {
Warn3("waitpid("F_pid", %p, 0): %s",
sock->stream.para.exec.pid, &status, strerror(errno));
}
Alarm(0);
}
} else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_RECVFROM) {
if (how >= 1) {
if (Close(sock->stream.fd) < 0) {
Info2("close(%d): %s",
sock->stream.fd, strerror(errno));
}
sock->stream.eof = 2;
sock->stream.fd = -1;
}
#endif /* WITH_SOCKET */
#if 0
} else {
Error1("xioshutdown(): bad data type specification %d", sock->stream.dtype);
return -1;
#endif
}
#if 0
else if (sock->stream.howtoend == END_CLOSE &&
sock->stream.dtype == DATA_STREAM) {
return result; return result;
} }
/* let us bring how nearer to the resulting action */
if ((sock->stream.flags&XIO_ACCMODE) == XIO_WRONLY) {
how = ((how+1) & ~(SHUT_RD+1)) - 1;
} else if ((sock->stream.flags&XIO_ACCMODE) == XIO_RDONLY) {
how = ((how+1) & ~(SHUT_WR+1)) - 1;
}
/* here handle special shutdown functions */
switch (sock->stream.howtoshut) {
#if WITH_OPENSSL
case XIOSHUT_OPENSSL:
sycSSL_shutdown(sock->stream.para.openssl.ssl);
/*! what about half/full close? */
return 0;
#endif /* WITH_OPENSSL */
default: break;
}
if (how == SHUT_RDWR) {
/* in this branch we handle only shutdown actions where read and write
shutdown are not independent */
switch (sock->stream.howtoshut) {
#if 0
case XIODATA_STREAM:
switch (sock->stream.howtoclose) {
#if WITH_SOCKET
case END_SHUTDOWN:
if ((result = Shutdown(sock->stream.fd1, how)) < 0) {
Info3("shutdown(%d, %d): %s",
sock->stream.fd1, how, strerror(errno));
}
break;
case END_SHUTDOWN_KILL:
if ((result = Shutdown(sock->stream.fd1, how)) < 0) {
Info3("shutdown(%d, %d): %s",
sock->stream.fd1, how, strerror(errno));
}
break;
#endif /* WITH_SOCKET */
case END_CLOSE:
Close(sock->stream.fd1);
#if WITH_TERMIOS #if WITH_TERMIOS
if (sock->stream.ttyvalid) { if (sock->stream.ttyvalid) {
if (Tcsetattr(sock->stream.fd, 0, &sock->stream.savetty) < 0) { if (Tcsetattr(sock->stream.fd1, 0, &sock->stream.savetty) < 0) {
Warn2("cannot restore terminal settings on fd %d: %s", Warn2("cannot restore terminal settings on fd %d: %s",
sock->stream.fd, strerror(errno)); sock->stream.fd1, strerror(errno));
} }
} }
#endif /* WITH_TERMIOS */ #endif /* WITH_TERMIOS */
/*PASSTHROUGH*/
case END_NONE:
break;
default:
Error1("xioshutdown(): bad end action 0x%x", sock->stream.howtoclose);
return -1;
}
#if WITH_SOCKET
case XIODATA_RECVFROM:
if (how >= 1) {
if (Close(sock->stream.fd1) < 0) {
Info2("close(%d): %s",
sock->stream.fd1, strerror(errno));
}
sock->stream.eof = 2;
sock->stream.fd1 = -1;
}
break;
#endif /* WITH_SOCKET */
#endif /* 0 */
default:
Error1("xioshutdown(): bad data type specification 0x%x", sock->stream.dtype);
return -1;
}
}
if ((how+1) & 1) { /* contains SHUT_RD */
switch (sock->stream.dtype & XIODATA_READMASK) {
/* shutdown read channel */
case XIOREAD_STREAM:
case XIODATA_2PIPE:
if (Close(sock->stream.fd1) < 0) {
Info2("close(%d): %s",
sock->stream.fd1, strerror(errno));
}
break;
}
}
if ((how+1) & 2) { /* contains SHUT_WR */
/* shutdown write channel */
int fd;
if (sock->stream.fdtype == FDTYPE_DOUBLE) {
fd = sock->stream.fd2;
} else {
fd = sock->stream.fd1;
}
switch (sock->stream.howtoshut & XIOSHUTWR_MASK) {
case XIOSHUTWR_CLOSE:
if (Close(fd) < 0) {
Info2("close(%d): %s", fd, strerror(errno));
}
/*PASSTHROUGH*/
case XIOSHUTWR_NONE:
break;
#if WITH_SOCKET
case XIOSHUTWR_DOWN:
if (Shutdown(fd, SHUT_WR) < 0) {
Info2("shutdown(%d, SHUT_WR): %s", fd, strerror(errno));
}
break;
#endif /* WITH_SOCKET */
#if 0
case XIOSHUTWR_DOWN_KILL:
if (Shutdown(fd, SHUT_WR) < 0) {
Info2("shutdown(%d, SHUT_WR): %s", fd, strerror(errno));
}
#endif #endif
case XIOSHUTWR_SIGHUP:
/* the child process might want to flush some data before
terminating */
xioshut_sleep_kill(sock->stream.child.pid, 0, SIGHUP);
break;
case XIOSHUTWR_SIGTERM:
/* the child process might want to flush some data before
terminating */
xioshut_sleep_kill(sock->stream.child.pid, 1000000, SIGTERM);
break;
case XIOSHUTWR_SIGKILL:
/* the child process might want to flush some data before
terminating */
xioshut_sleep_kill(sock->stream.child.pid, 1000000, SIGKILL);
break;
default:
Error1("xioshutdown(): unhandled howtoshut=0x%x during SHUT_WR",
sock->stream.howtoshut);
}
}
return result; return result;
} }
/* wait some time and then send signal to sub process. This is useful after
shutting down the connection to give process some time to flush its output
data */
static int xioshut_sleep_kill(pid_t sub, unsigned long usec, int sig) {
struct sigaction act;
int status = 0;
/* we wait for the child process to die, but to prevent timeout
we raise an alarm after some time. */
/* NOTE: the alarm does not terminate waitpid() on Linux/glibc
(BUG?),
therefore we have to do the kill in the signal handler */
Signal(SIGALRM, signal_kill_pid);
socat_kill_pid = sub;
#if HAVE_SETITIMER
/*! with next feature release, we get usec resolution and an option
*/
#else
Alarm(1 /*! sock->stream.child.waitdie */);
#endif /* !HAVE_SETITIMER */
if (Waitpid(sub, &status, 0) < 0) {
Warn3("waitpid("F_pid", %p, 0): %s",
sub, &status, strerror(errno));
}
Alarm(0);
return 0;
}

View file

@ -1,5 +1,5 @@
/* $Id: xiosigchld.c,v 1.21 2006/12/28 14:38:38 gerhard Exp $ */ /* $Id: xiosigchld.c,v 1.21 2006/12/28 14:38:38 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2006 */ /* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this is the source of the extended child signal handler */ /* this is the source of the extended child signal handler */
@ -7,23 +7,42 @@
#include "xiosysincludes.h" #include "xiosysincludes.h"
#include "xioopen.h" #include "xioopen.h"
#include "xiosigchld.h"
/*****************************************************************************/
/* we maintain a table of all known child processes */
/* for now, we use a very primitive data structure - just an unsorted, size
limited array */
/*!! with socat, at most 4 exec children exist */ #define XIO_MAXCHILDPIDS 16
struct _xiosigchld_child {
pid_t pid;
void (*sigaction)(int, siginfo_t *, void *);
void *context;
} ;
static struct _xiosigchld_child * _xiosigchld_find(pid_t pid);
static struct _xiosigchld_child xio_childpids[XIO_MAXCHILDPIDS];
#if 1 /*!!!*/
/*!! with socat, at most 4 managed children exist */
pid_t diedunknown1; /* child died before it is registered */ pid_t diedunknown1; /* child died before it is registered */
pid_t diedunknown2; pid_t diedunknown2;
pid_t diedunknown3; pid_t diedunknown3;
pid_t diedunknown4; pid_t diedunknown4;
#endif
/* register for a xio filedescriptor a callback (handler). /* register for a xio filedescriptor a callback (handler).
when a SIGCHLD occurs, the signal handler will ??? */ when a SIGCHLD occurs, the signal handler will ??? */
int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)) { int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)) {
if (xfd->tag != XIO_TAG_DUAL) { if (xfd->tag != XIO_TAG_DUAL) {
xfd->stream.sigchild = callback; xfd->stream.child.sigchild = callback;
} else { } else {
xfd->dual.stream[0]->sigchild = callback; xfd->dual.stream[0]->child.sigchild = callback;
xfd->dual.stream[1]->sigchild = callback; xfd->dual.stream[1]->child.sigchild = callback;
} }
return 0; return 0;
} }
@ -31,9 +50,9 @@ int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)) {
/* exec'd child has died, perform appropriate changes to descriptor */ /* exec'd child has died, perform appropriate changes to descriptor */
static int sigchld_stream(struct single *file) { static int sigchld_stream(struct single *file) {
/*!! call back to application */ /*!! call back to application */
file->para.exec.pid = 0; file->child.pid = 0;
if (file->sigchild) { if (file->child.sigchild) {
return (*file->sigchild)(file); return (*file->child.sigchild)(file);
} }
return 0; return 0;
} }
@ -43,12 +62,9 @@ static int xio_checkchild(xiofile_t *socket, int socknum, pid_t deadchild) {
int retval; int retval;
if (socket != NULL) { if (socket != NULL) {
if (socket->tag != XIO_TAG_DUAL) { if (socket->tag != XIO_TAG_DUAL) {
if ((socket->stream.howtoend == END_KILL || if (socket->stream.child.pid == deadchild) {
socket->stream.howtoend == END_CLOSE_KILL ||
socket->stream.howtoend == END_SHUTDOWN_KILL) &&
socket->stream.para.exec.pid == deadchild) {
Info2("exec'd process %d on socket %d terminated", Info2("exec'd process %d on socket %d terminated",
socket->stream.para.exec.pid, socknum); socket->stream.child.pid, socknum);
sigchld_stream(&socket->stream); sigchld_stream(&socket->stream);
return 1; return 1;
} }
@ -64,17 +80,22 @@ static int xio_checkchild(xiofile_t *socket, int socknum, pid_t deadchild) {
/* this is the "physical" signal handler for SIGCHLD */ /* this is the "physical" signal handler for SIGCHLD */
/* the current socat/xio implementation knows two kinds of children: /* the current socat/xio implementation knows two kinds of children:
exec/system addresses perform a fork: these children are registered and exec/system addresses perform a fork: their children are registered and
there death influences the parents flow; their death's influence the parents' flow;
listen-socket with fork children: these children are "anonymous" and their listen-socket with fork children: these children are "anonymous" and their
death does not affect the parent process (now; maybe we have a child death does not affect the parent process (now; maybe we have a child
process counter later) */ process counter later) */
void childdied(int signum) { void childdied(int signum
#if HAVE_SIGACTION
, siginfo_t *siginfo, void *context
#endif /* HAVE_SIGACTION */
) {
pid_t pid; pid_t pid;
int _errno; int _errno;
int status = 0; int status = 0;
bool wassig = false; bool wassig = false;
int i; int i;
struct _xiosigchld_child *entry;
_errno = errno; /* save current value; e.g., select() on Cygwin seems _errno = errno; /* save current value; e.g., select() on Cygwin seems
to set it to EINTR _before_ handling the signal, and to set it to EINTR _before_ handling the signal, and
@ -105,6 +126,7 @@ void childdied(int signum) {
errno = _errno; errno = _errno;
return; return;
} }
#if 0
/*! indent */ /*! indent */
/* check if it was a registered child process */ /* check if it was a registered child process */
i = 0; i = 0;
@ -128,6 +150,15 @@ void childdied(int signum) {
Debug("saving pid in diedunknown4"); Debug("saving pid in diedunknown4");
} }
} }
#else
entry = _xiosigchld_find(pid);
if (entry == NULL) {
Info("dead child "F_pid" died unknown");
} else {
(*entry->sigaction)(signum, siginfo, entry->context);
xiosigchld_unregister(pid);
}
#endif
if (WIFEXITED(status)) { if (WIFEXITED(status)) {
if (WEXITSTATUS(status) == 0) { if (WEXITSTATUS(status) == 0) {
@ -157,3 +188,107 @@ void childdied(int signum) {
Info("childdied() finished"); Info("childdied() finished");
errno = _errno; errno = _errno;
} }
/* search for given pid in child process table. returns matching entry on
success, or NULL if not found. Can be used with pid==0 to look for an empty
entry. */
static struct _xiosigchld_child *
_xiosigchld_find(pid_t pid) {
int i;
/* is it already registered? */
for (i = 0; i < XIO_MAXCHILDPIDS; ++i) {
if (pid == xio_childpids[i].pid) {
return &xio_childpids[i];
}
}
return NULL;
}
/* add a child process to the table
returns 0 on success (registered or reregistered child)
returns -1 on table overflow
*/
int xiosigchld_register(pid_t pid,
void (*sigaction)(int, siginfo_t *, void *),
void *context) {
struct _xiosigchld_child *entry;
/* is it already registered? */
if (entry = _xiosigchld_find(pid)) {
/* was already registered, override */
entry->sigaction = sigaction;
entry->context = context;
return 0;
}
/* try to register it */
if (entry = _xiosigchld_find(0)) {
entry->pid = pid;
entry->sigaction = sigaction;
entry->context = context;
return 0;
}
Warn("xiosigchld_register(): table overflow");
return -1;
}
/* remove a child process to the table
returns 0 on success
returns 1 if pid was not found in table
*/
int xiosigchld_unregister(pid_t pid) {
struct _xiosigchld_child *entry;
/* is it already registered? */
if (entry = _xiosigchld_find(pid)) {
/* found, remove it from table */
entry->pid = 0;
return 0;
}
return 1;
}
/* clear the child process table */
/* especially interesting after fork() in child process
returns 0
*/
int xiosigchld_clearall(void) {
int i;
for (i = 0; i < XIO_MAXCHILDPIDS; ++i) {
xio_childpids[i].pid = 0;
}
return 0;
}
void xiosigaction_subaddr_ok(int signum, siginfo_t *siginfo, void *ucontext) {
pid_t subpid = siginfo->si_pid;
struct _xiosigchld_child *entry;
xiosingle_t *xfd;
entry = _xiosigchld_find(subpid);
if (entry == NULL) {
Warn1("SIGUSR1 from unregistered process "F_pid, subpid);
return;
}
xfd = entry->context;
xfd->subaddrstat = 1;
}
void xiosigaction_child(int signum, siginfo_t *siginfo, void *ucontext) {
pid_t subpid = siginfo->si_pid;
xiosingle_t *xfd = ucontext;
/* the sub process that is connected to this xio address has terminated */
Notice2("sub process "F_pid" died, setting in xfd %p", subpid, xfd);
xfd->subaddrstat = -1;
xfd->subaddrexit = siginfo->si_status;
if (xfd->child.sigchild) {
(*xfd->child.sigchild)(xfd);
}
}

30
xiosigchld.h Normal file
View file

@ -0,0 +1,30 @@
/* $Id$ */
/* Copyright Gerhard Rieger 2006 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xiosigchld_h
#define __xiosigchld_h 1
extern pid_t diedunknown1; /* child died before it is registered */
extern pid_t diedunknown2;
extern pid_t diedunknown3;
extern pid_t diedunknown4;
extern int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *));
extern void childdied(int signum
#if HAVE_SIGACTION
, siginfo_t *siginfo, void *context
#endif /* HAVE_SIGACTION */
);
extern int
xiosigchld_register(pid_t pid,
void (*sigaction)(int, siginfo_t *, void *),
void *context);
extern int xiosigchld_unregister(pid_t pid);
extern int xiosigchld_clearall(void);
extern void xiosigaction_subaddr_ok(int signum, siginfo_t *siginfo, void *ucontext);
extern void xiosigaction_child(int signum, siginfo_t *siginfo, void *ucontext);
#endif /* !defined(__xiosigchld_h) */

186
xiosocketpair.c Normal file
View file

@ -0,0 +1,186 @@
/* $Id$ */
/* Copyright Gerhard Rieger 2007 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this is the source of the internal xiosocketpair function */
#include "xiosysincludes.h"
#include "sycls.h"
#include "error.h"
#include "xio.h"
#if defined(HAVE_DEV_PTMX)
# define PTMX "/dev/ptmx" /* Linux */
#elif HAVE_DEV_PTC
# define PTMX "/dev/ptc" /* AIX */
#endif
#define MAXPTYNAMELEN 64
/* how: 0...socketpair; 1...pipes pair; 2...pty (master, slave)
how==0: var args (int)domain, (int)type, (int)protocol
how==1: no var args
how==2: var args (int)useptmx
returns -1 on error or 0 on success */
int xiosocketpair(xiofile_t **xfd1p, xiofile_t **xfd2p, int how, ...) {
va_list ap;
xiofile_t *xfd1, *xfd2;
int result = 0;
if ((xfd1 = xioallocfd()) == NULL) {
return -1;
}
if ((xfd2 = xioallocfd()) == NULL) {
xiofreefd(xfd1);
return -1;
}
switch (how) {
case 0: /* socketpair */
{
int sv[2];
int domain, type, protocol;
va_start(ap, how);
domain = va_arg(ap, int);
type = va_arg(ap, int);
protocol = va_arg(ap, int);
va_end(ap);
if (Socketpair(domain, type, protocol, sv) < 0) {
Error5("socketpair(%d, %d, %d, %p): %s",
domain, type, protocol, sv, strerror(errno));
xiofreefd(xfd1); xiofreefd(xfd2);
return -1;
}
assert(xfd1->stream.fdtype == FDTYPE_SINGLE);
xfd1->stream.fd1 = sv[0];
assert(xfd2->stream.fdtype == FDTYPE_SINGLE);
xfd2->stream.fd1 = sv[1];
}
break;
case 1:
{
int filedes1[2], filedes2[2];
if (Pipe(filedes1) < 0) {
Error2("pipe(%p): %s", filedes1, strerror(errno));
xiofreefd(xfd1); xiofreefd(xfd2);
return -1;
}
if (Pipe(filedes2) < 0) {
Error2("pipe(%p): %s", filedes2, strerror(errno));
xiofreefd(xfd1); xiofreefd(xfd2);
Close(filedes1[0]); Close(filedes1[1]);
return -1;
}
xfd1->stream.fd1 = filedes1[0];
xfd1->stream.fd2 = filedes2[1];
xfd1->stream.fdtype = FDTYPE_DOUBLE;
xfd1->stream.dtype = XIODATA_2PIPE;
xfd2->stream.fd1 = filedes2[0];
xfd2->stream.fd2 = filedes1[1];
xfd2->stream.fdtype = FDTYPE_DOUBLE;
xfd2->stream.dtype = XIODATA_2PIPE;
}
break;
#if HAVE_DEV_PTMX || HAVE_DEV_PTC
case 2: /* pty (master, slave) */
{
int useptmx;
char ptyname[MAXPTYNAMELEN];
int ptyfd = -1, ttyfd;
va_start(ap, how);
useptmx = va_arg(ap, int);
va_end(ap);
if (useptmx) {
if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) {
Warn1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620): %s",
strerror(errno));
/*!*/
} else {
;/*0 Info1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620) -> %d", ptyfd);*/
}
if (ptyfd >= 0) {
char *tn = NULL;
/* we used PTMX before forking */
/*0 extern char *ptsname(int);*/
#if HAVE_GRANTPT /* AIX, not Linux */
if (Grantpt(ptyfd)/*!*/ < 0) {
Warn2("grantpt(%d): %s", ptyfd, strerror(errno));
}
#endif /* HAVE_GRANTPT */
#if HAVE_UNLOCKPT
if (Unlockpt(ptyfd)/*!*/ < 0) {
Warn2("unlockpt(%d): %s", ptyfd, strerror(errno));
}
#endif /* HAVE_UNLOCKPT */
#if HAVE_PTSNAME /* AIX, not Linux */
if ((tn = Ptsname(ptyfd)) == NULL) {
Warn2("ptsname(%d): %s", ptyfd, strerror(errno));
} else {
Notice1("PTY is %s", tn);
}
#endif /* HAVE_PTSNAME */
#if 0
if (tn == NULL) {
/*! ttyname_r() */
if ((tn = Ttyname(ptyfd)) == NULL) {
Warn2("ttyname(%d): %s", ptyfd, strerror(errno));
}
}
strncpy(ptyname, tn, MAXPTYNAMELEN);
#endif
if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) {
Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno));
} else {
/*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/
}
#ifdef I_PUSH
/* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */
/* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */
/* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
/* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
if (Ioctl(ttyfd, I_FIND, "ldterm") == 0) {
Ioctl(ttyfd, I_PUSH, "ptem"); /* 0 */
Ioctl(ttyfd, I_PUSH, "ldterm"); /* 0 */
Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */
}
#endif
}
}
#if HAVE_OPENPTY
if (ptyfd < 0) {
int result;
if ((result = Openpty(&ptyfd, &ttyfd, ptyname, NULL, NULL)) < 0) {
Error4("openpty(%p, %p, %p, NULL, NULL): %s",
&ptyfd, &ttyfd, ptyname, strerror(errno));
return -1;
}
Notice1("PTY is %s", ptyname);
}
#endif /* HAVE_OPENPTY */
assert(xfd1->stream.fdtype == FDTYPE_SINGLE);
xfd1->stream.fd1 = ttyfd;
assert(xfd2->stream.fdtype == FDTYPE_SINGLE);
xfd2->stream.fd1 = ptyfd;
}
break;
#endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */
default:
Error1("undefined socketpair mechanism %d", how);
xiofreefd(xfd1); xiofreefd(xfd2);
return -1;
}
*xfd1p = xfd1;
*xfd2p = xfd2;
return 0;
}

11
xiostatic.h Normal file
View file

@ -0,0 +1,11 @@
/* $Id$ */
/* Copyright Gerhard Rieger 2006 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* libxio internal global variables */
#ifndef __xiostatic_h
#define __xiostatic_h 1
extern int xio_flags;
#endif /* !defined(__xiostatic_h) */

302
xiotransfer.c Normal file
View file

@ -0,0 +1,302 @@
/* $Id$ */
/* Copyright Gerhard Rieger 2007 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this is the source file of the data transfer function */
#include "xiosysincludes.h"
#include "mytypes.h"
#include "compat.h"
#include "error.h"
#include "sycls.h"
#include "xio.h"
static
int cv_newline(unsigned char **buff, ssize_t *bytes, int lineterm1, int lineterm2);
#define MAXTIMESTAMPLEN 128
/* prints the timestamp to the buffer and terminates it with '\0'. This buffer
should be at least MAXTIMESTAMPLEN bytes long.
returns 0 on success or -1 if an error occurred */
int gettimestamp(char *timestamp) {
size_t bytes;
#if HAVE_GETTIMEOFDAY || 1
struct timeval now;
int result;
time_t nowt;
#else /* !HAVE_GETTIMEOFDAY */
time_t now;
#endif /* !HAVE_GETTIMEOFDAY */
#if HAVE_GETTIMEOFDAY || 1
result = gettimeofday(&now, NULL);
if (result < 0) {
return result;
} else {
nowt = now.tv_sec;
#if HAVE_STRFTIME
bytes = strftime(timestamp, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt));
bytes += sprintf(timestamp+19, "."F_tv_usec" ", now.tv_usec);
#else
strcpy(timestamp, ctime(&nowt));
bytes = strlen(timestamp);
#endif
}
#else /* !HAVE_GETTIMEOFDAY */
now = time(NULL); if (now == (time_t)-1) {
return -1;
} else {
#if HAVE_STRFTIME
bytes = strftime(timestamp, 21, "%Y/%m/%d %H:%M:%S ", localtime(&now));
#else
strcpy(timestamp, ctime(&now));
bytes = strlen(timestamp);
#endif
}
#endif /* !HAVE_GETTIMEOFDAY */
return 0;
}
static const char *prefixltor = "> ";
static const char *prefixrtol = "< ";
static unsigned long numltor;
static unsigned long numrtol;
/* print block header (during verbose or hex dump)
returns 0 on success or -1 if an error occurred */
static int
xioprintblockheader(FILE *file, size_t bytes, bool righttoleft) {
char timestamp[MAXTIMESTAMPLEN];
char buff[128+MAXTIMESTAMPLEN];
if (gettimestamp(timestamp) < 0) {
return -1;
}
if (righttoleft) {
sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
prefixrtol, timestamp, bytes, numrtol, numrtol+bytes-1);
numrtol+=bytes;
} else {
sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
prefixltor, timestamp, bytes, numltor, numltor+bytes-1);
numltor+=bytes;
}
fputs(buff, file);
return 0;
}
/* inpipe is suspected to have read data available; read at most bufsiz bytes
and transfer them to outpipe. Perform required data conversions.
buff should be at least twice as large as bufsiz, to allow all standard
conversions. Returns the number of bytes written, or 0 on EOF or <0 if an
error occurred or when data was read but none written due to conversions
(with EAGAIN). EAGAIN also occurs when reading from a nonblocking FD where
the file has a mandatory lock.
If 0 bytes were read (EOF), it does NOT shutdown or close a channel, and it
does NOT write a zero bytes block.
*/
/* inpipe, outpipe must be single descriptors (not dual!) */
int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
unsigned char **buff, size_t bufsiz, bool righttoleft) {
ssize_t bytes, writt;
bytes = xioread(inpipe, *buff, bufsiz);
if (bytes < 0) {
if (errno != EAGAIN)
XIO_RDSTREAM(inpipe)->eof = 2;
/*xioshutdown(inpipe, SHUT_RD);*/
return -1;
}
if (bytes == 0) {
writt = 0;
}
else /* if (bytes > 0)*/ {
if (XIO_RDSTREAM(inpipe)->lineterm !=
XIO_WRSTREAM(outpipe)->lineterm) {
cv_newline(buff, &bytes,
XIO_RDSTREAM(inpipe)->lineterm,
XIO_WRSTREAM(outpipe)->lineterm);
}
if (bytes == 0) {
errno = EAGAIN; return -1;
}
if (xioparams->verbose && xioparams->verbhex) {
/* Hack-o-rama */
size_t i = 0;
size_t j;
size_t N = 16;
const unsigned char *end, *s, *t;
s = *buff;
end = (*buff)+bytes;
xioprintblockheader(stderr, bytes, righttoleft);
while (s < end) {
/*! prefix? */
j = Min(N, (size_t)(end-s));
/* print hex */
t = s;
i = 0;
while (i < j) {
int c = *t++;
fprintf(stderr, " %02x", c);
++i;
if (c == '\n') break;
}
/* fill hex column */
while (i < N) {
fputs(" ", stderr);
++i;
}
fputs(" ", stderr);
/* print acsii */
t = s;
i = 0;
while (i < j) {
int c = *t++;
if (c == '\n') {
fputc('.', stderr);
break;
}
if (!isprint(c))
c = '.';
fputc(c, stderr);
++i;
}
fputc('\n', stderr);
s = t;
}
fputs("--\n", stderr);
} else if (xioparams->verbose) {
size_t i = 0;
xioprintblockheader(stderr, bytes, righttoleft);
while (i < (size_t)bytes) {
int c = (*buff)[i];
if (i > 0 && (*buff)[i-1] == '\n')
/*! prefix? */;
switch (c) {
case '\a' : fputs("\\a", stderr); break;
case '\b' : fputs("\\b", stderr); break;
case '\t' : fputs("\t", stderr); break;
case '\n' : fputs("\n", stderr); break;
case '\v' : fputs("\\v", stderr); break;
case '\f' : fputs("\\f", stderr); break;
case '\r' : fputs("\\r", stderr); break;
case '\\' : fputs("\\\\", stderr); break;
default:
if (!isprint(c))
c = '.';
fputc(c, stderr);
break;
}
++i;
}
} else if (xioparams->verbhex) {
int i;
/*! prefix? */
for (i = 0; i < bytes; ++i) {
fprintf(stderr, " %02x", (*buff)[i]);
}
fputc('\n', stderr);
}
writt = xiowrite(outpipe, *buff, bytes);
if (writt < 0) {
/* EAGAIN when nonblocking but a mandatory lock is on file.
the problem with EAGAIN is that the read cannot be repeated,
so we need to buffer the data and try to write it later
again. not yet implemented, sorry. */
#if 0
if (errno == EPIPE) {
return 0; /* can no longer write; handle like EOF */
}
#endif
return -1;
} else {
Info3("transferred "F_Zu" bytes from %d to %d",
writt, XIO_GETRDFD(inpipe), XIO_GETWRFD(outpipe));
}
}
return writt;
}
#define CR '\r'
#define LF '\n'
static int cv_newline(unsigned char **buff, ssize_t *bytes,
int lineterm1, int lineterm2) {
/* must perform newline changes */
if (lineterm1 <= LINETERM_CR && lineterm2 <= LINETERM_CR) {
/* no change in data length */
unsigned char from, to, *p, *z;
if (lineterm1 == LINETERM_RAW) {
from = '\n'; to = '\r';
} else {
from = '\r'; to = '\n';
}
z = *buff + *bytes;
p = *buff;
while (p < z) {
if (*p == from) *p = to;
++p;
}
} else if (lineterm1 == LINETERM_CRNL) {
/* buffer becomes shorter */
unsigned char to, *s, *t, *z;
if (lineterm2 == LINETERM_RAW) {
to = '\n';
} else {
to = '\r';
}
z = *buff + *bytes;
s = t = *buff;
while (s < z) {
if (*s == '\r') {
++s;
continue;
}
if (*s == '\n') {
*t++ = to; ++s;
} else {
*t++ = *s++;
}
}
*bytes = t - *buff;
} else {
/* buffer becomes longer, must alloc another space */
unsigned char *buf2;
unsigned char from; unsigned char *s, *t, *z;
if (lineterm1 == LINETERM_RAW) {
from = '\n';
} else {
from = '\r';
}
if ((buf2 = Malloc(2*xioparams->bufsiz + 1)) == NULL) {
return -1;
}
s = *buff; t = buf2; z = *buff + *bytes;
while (s < z) {
if (*s == from) {
*t++ = '\r'; *t++ = '\n';
++s;
continue;
} else {
*t++ = *s++;
}
}
free(*buff);
*buff = buf2;
*bytes = t - buf2;;
}
return 0;
}

View file

@ -8,6 +8,7 @@
#include "xiosysincludes.h" #include "xiosysincludes.h"
#include "xioopen.h" #include "xioopen.h"
#include "xio-test.h"
#include "xio-readline.h" #include "xio-readline.h"
#include "xio-openssl.h" #include "xio-openssl.h"
@ -20,6 +21,7 @@
ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) { ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
ssize_t writt; ssize_t writt;
struct single *pipe; struct single *pipe;
int fd;
int _errno; int _errno;
if (file->tag == XIO_TAG_INVALID) { if (file->tag == XIO_TAG_INVALID) {
@ -46,11 +48,13 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
} }
#endif /* WITH_READLINE */ #endif /* WITH_READLINE */
fd = XIO_GETWRFD(file);
switch (pipe->dtype & XIODATA_WRITEMASK) { switch (pipe->dtype & XIODATA_WRITEMASK) {
case XIOWRITE_STREAM: case XIOWRITE_STREAM:
do { do {
writt = Write(pipe->fd, buff, bytes); writt = Write(fd, buff, bytes);
} while (writt < 0 && errno == EINTR); } while (writt < 0 && errno == EINTR);
if (writt < 0) { if (writt < 0) {
_errno = errno; _errno = errno;
@ -59,13 +63,13 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
case ECONNRESET: case ECONNRESET:
if (pipe->cool_write) { if (pipe->cool_write) {
Notice4("write(%d, %p, "F_Zu"): %s", Notice4("write(%d, %p, "F_Zu"): %s",
pipe->fd, buff, bytes, strerror(_errno)); fd, buff, bytes, strerror(_errno));
break; break;
} }
/*PASSTRHOUGH*/ /*PASSTRHOUGH*/
default: default:
Error4("write(%d, %p, "F_Zu"): %s", Error4("write(%d, %p, "F_Zu"): %s",
pipe->fd, buff, bytes, strerror(_errno)); fd, buff, bytes, strerror(_errno));
} }
errno = _errno; errno = _errno;
return -1; return -1;
@ -85,14 +89,14 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
/*socklen_t fromlen;*/ /*socklen_t fromlen;*/
do { do {
writt = Sendto(pipe->fd, buff, bytes, 0, writt = Sendto(fd, buff, bytes, 0,
&pipe->peersa.soa, pipe->salen); &pipe->peersa.soa, pipe->salen);
} while (writt < 0 && errno == EINTR); } while (writt < 0 && errno == EINTR);
if (writt < 0) { if (writt < 0) {
char infobuff[256]; char infobuff[256];
_errno = errno; _errno = errno;
Error6("sendto(%d, %p, "F_Zu", 0, %s, "F_socklen"): %s", Error6("sendto(%d, %p, "F_Zu", 0, %s, "F_socklen"): %s",
pipe->fd, buff, bytes, fd, buff, bytes,
sockaddr_info(&pipe->peersa.soa, pipe->salen, sockaddr_info(&pipe->peersa.soa, pipe->salen,
infobuff, sizeof(infobuff)), infobuff, sizeof(infobuff)),
pipe->salen, strerror(_errno)); pipe->salen, strerror(_errno));
@ -102,7 +106,7 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
if ((size_t)writt < bytes) { if ((size_t)writt < bytes) {
char infobuff[256]; char infobuff[256];
Warn7("sendto(%d, %p, "F_Zu", 0, %s, "F_socklen") only wrote "F_Zu" of "F_Zu" bytes", Warn7("sendto(%d, %p, "F_Zu", 0, %s, "F_socklen") only wrote "F_Zu" of "F_Zu" bytes",
pipe->fd, buff, bytes, fd, buff, bytes,
sockaddr_info(&pipe->peersa.soa, pipe->salen, sockaddr_info(&pipe->peersa.soa, pipe->salen,
infobuff, sizeof(infobuff)), infobuff, sizeof(infobuff)),
pipe->salen, writt, bytes); pipe->salen, writt, bytes);
@ -112,7 +116,7 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
char infobuff[256]; char infobuff[256];
union sockaddr_union us; union sockaddr_union us;
socklen_t uslen = sizeof(us); socklen_t uslen = sizeof(us);
Getsockname(pipe->fd, &us.soa, &uslen); Getsockname(fd, &us.soa, &uslen);
Notice1("local address: %s", Notice1("local address: %s",
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff))); sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)));
} }
@ -120,13 +124,14 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
#endif /* WITH_SOCKET */ #endif /* WITH_SOCKET */
case XIOWRITE_PIPE: case XIOWRITE_PIPE:
case XIOWRITE_2PIPE:
do { do {
writt = Write(pipe->para.bipipe.fdout, buff, bytes); writt = Write(fd, buff, bytes);
} while (writt < 0 && errno == EINTR); } while (writt < 0 && errno == EINTR);
_errno = errno; _errno = errno;
if (writt < 0) { if (writt < 0) {
Error4("write(%d, %p, "F_Zu"): %s", Error4("write(%d, %p, "F_Zu"): %s",
pipe->para.bipipe.fdout, buff, bytes, strerror(_errno)); fd, buff, bytes, strerror(_errno));
errno = _errno; errno = _errno;
return -1; return -1;
} }
@ -136,22 +141,14 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
} }
break; break;
case XIOWRITE_2PIPE: #if WITH_TEST
do { case XIOWRITE_TEST:
writt = Write(pipe->para.exec.fdout, buff, bytes); /* this function prints its own error messages */
} while (writt < 0 && errno == EINTR); return xiowrite_test(pipe, buff, bytes);
_errno = errno; case XIOWRITE_TESTREV:
if (writt < 0) { /* this function prints its own error messages */
Error4("write(%d, %p, "F_Zu"): %s", return xiowrite_testrev(pipe, buff, bytes);
pipe->para.exec.fdout, buff, bytes, strerror(_errno)); #endif /* WITH_TEST */
errno = _errno;
return -1;
}
if ((size_t)writt < bytes) {
Warn2("write() only processed "F_Zu" of "F_Zu" bytes",
writt, bytes);
}
break;
#if WITH_OPENSSL #if WITH_OPENSSL
case XIOWRITE_OPENSSL: case XIOWRITE_OPENSSL: