From db717446a4a01121927a74017863dc40b2faf2b5 Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Sun, 17 Feb 2008 14:59:16 +0100 Subject: [PATCH] version 2.0.0-b1 --- CHANGES | 28 ++ EXAMPLES | 20 +- FAQ | 8 - Makefile.in | 37 +- VERSION | 2 +- compat.h | 4 +- config.h.in | 4 + configure.in | 16 + doc/socat.1 | 489 +++++----------------- doc/socat.html | 528 +++++------------------- error.c | 7 +- ftp.sh | 2 +- nestlex.c | 31 +- nestlex.h | 6 +- procan.c | 2 +- socat.c | 284 ++++++------- sslcls.c | 16 + sslcls.h | 4 + sycls.c | 111 ++++- sycls.h | 21 + sysincludes.h | 3 +- sysutils.c | 4 +- sysutils.h | 12 +- test.sh | 431 +++++++++++++++----- xio-creat.c | 20 +- xio-creat.h | 6 +- xio-exec.c | 27 +- xio-exec.h | 6 +- xio-fd.c | 5 +- xio-fd.h | 3 +- xio-fdnum.c | 72 +++- xio-fdnum.h | 9 +- xio-file.c | 25 +- xio-file.h | 6 +- xio-gopen.c | 92 +++-- xio-gopen.h | 7 +- xio-ipapp.c | 19 +- xio-listen.c | 78 ++-- xio-nop.c | 64 +++ xio-nop.h | 10 + xio-openssl.c | 315 +++++++++++---- xio-openssl.h | 4 +- xio-pipe.c | 50 +-- xio-pipe.h | 6 +- xio-progcall.c | 760 ++++++++++++++++++++++++++++++++-- xio-progcall.h | 9 +- xio-proxy.c | 149 +++++-- xio-proxy.h | 6 +- xio-pty.c | 33 +- xio-pty.h | 6 +- xio-rawip.c | 49 ++- xio-rawip.h | 24 +- xio-readline.c | 48 ++- xio-readline.h | 6 +- xio-socket.c | 169 ++++---- xio-socket.h | 2 +- xio-socks.c | 116 ++++-- xio-socks.h | 19 +- xio-socks5.c | 505 +++++++++++++++++++++++ xio-socks5.h | 107 +++++ xio-stdio.c | 70 ++-- xio-stdio.h | 13 +- xio-system.c | 12 +- xio-system.h | 6 +- xio-tcp.c | 26 +- xio-tcp.h | 16 +- xio-tcpwrap.c | 4 +- xio-test.c | 228 +++++++++++ xio-test.h | 16 + xio-tun.c | 24 +- xio-tun.h | 2 +- xio-udp.c | 110 ++--- xio-udp.h | 36 +- xio-unix.c | 50 +-- xio-unix.h | 24 +- xio.h | 311 +++++++++++--- xioclose.c | 85 ++-- xioconfig.h | 37 +- xioengine.c | 434 ++++++++++++++++++++ xiohelp.c | 60 ++- xioinitialize.c | 56 ++- xiolayer.c | 8 +- xiomodes.h | 3 + xioopen.c | 1030 ++++++++++++++++++++++++++++++++++++++--------- xioopen.h | 19 +- xioopts.c | 96 +++-- xioopts.h | 10 +- xioparam.c | 20 +- xioread.c | 60 ++- xioshutdown.c | 271 ++++++++----- xiosigchld.c | 167 +++++++- xiosigchld.h | 30 ++ xiosocketpair.c | 186 +++++++++ xiostatic.h | 11 + xiotransfer.c | 302 ++++++++++++++ xiowrite.c | 47 +-- 96 files changed, 6419 insertions(+), 2363 deletions(-) create mode 100644 xio-nop.c create mode 100644 xio-nop.h create mode 100644 xio-socks5.c create mode 100644 xio-socks5.h create mode 100644 xio-test.c create mode 100644 xio-test.h create mode 100644 xioengine.c create mode 100644 xiosigchld.h create mode 100644 xiosocketpair.c create mode 100644 xiostatic.h create mode 100644 xiotransfer.c diff --git a/CHANGES b/CHANGES index 8148136..06127d0 100644 --- a/CHANGES +++ b/CHANGES @@ -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: new features: diff --git a/EXAMPLES b/EXAMPLES index 57286ea..838522d 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -87,7 +87,7 @@ $ socat -u -,cr - // save piped data similar to 'tee': // 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 @@ -113,23 +113,23 @@ $ socat -,echo=0 open:/tmp/myfile,create,trunc,ignoreeof!!/tmp/myfile // forms of stdin with stdout, all equivalent $ socat echo - $ socat echo STDIO -$ socat echo STDIN!!STDOUT -$ socat echo STDIO!!STDIO -$ socat echo -!!- -$ socat echo FD:0!!FD:1 -$ socat echo 0!!1 -$ socat echo /dev/stdin!!/dev/stdout // if your OS provides these +$ socat echo STDOUT%STDIN +$ socat echo STDIO%STDIO +$ socat echo -%- +$ socat echo FD:1%FD:0 +$ socat echo 1%0 +$ socat echo /dev/stdout%/dev/stdin // if your OS provides these /////////////////////////////////////////////////////////////////////////////// // some echo address examples $ socat - PIPE $ 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 - SYSTEM:/bin/cat // another echo $ socat - TCP:loopback:7 // if inetd echo/TCP 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 - TCP:loopback:2000,bind=:2000 // Linux bug? # socat - IP:loopback:222 // raw protocol, self "connected" (attention, @@ -151,7 +151,7 @@ $ socat -u - CREATE:/tmp/outfile1,group=floppy,perm=0640 /////////////////////////////////////////////////////////////////////////////// // 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 diff --git a/FAQ b/FAQ index 66f2009..32d8f32 100644 --- a/FAQ +++ b/FAQ @@ -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. -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 with something like "ld.so.1: ./socat: fatal: libreadline.so.4: open failed: no such file or directory" diff --git a/Makefile.in b/Makefile.in index 4d76144..6667eed 100644 --- a/Makefile.in +++ b/Makefile.in @@ -37,18 +37,19 @@ INSTALL = @INSTALL@ #0 CFLAGS = @CFLAGS@ $(CCOPTS) $(DEFS) $(INCLS) CFLAGS = @CFLAGS@ $(CCOPTS) $(DEFS) $(CPPFLAGS) -CLIBS = $(LIBS) +CLIBS = $(LIBS) -lpthread #CLIBS = $(LIBS) -lm -lefence XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \ - xiosignal.c xiosigchld.c xioread.c xiowrite.c \ - xiolayer.c xioshutdown.c xioclose.c xioexit.c \ + xiosignal.c xiosigchld.c xioread.c xiowrite.c xiotransfer.c xioengine.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-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-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.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) UTLSRCS = error.c dalan.c procan.c hostan.c fdname.c sysutils.c utils.c nestlex.c @FILAN@ @SYCLS@ @SSLCLS@ 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 \ 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-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-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 doc/xio.help 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 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 TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \ proxy.sh socks4a-echo.sh testcert.conf -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.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.FreeBSD-6-1 Config/config.FreeBSD-6-1.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.Tru64-5-1B Config/config.Tru64-5-1B.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.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.FreeBSD-6-1 Config/config.FreeBSD-6-1.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.Tru64-5-1B Config/config.Tru64-5-1B.h all: progs @@ -133,7 +134,7 @@ socat.tar.bz2: socat.tar VERSION = `sed 's/"//g' 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 tar cf - $+ |(cd $(TARDIR); tar xf -) tar cvf socat.tar $(TARDIR) diff --git a/VERSION b/VERSION index 32c65da..7f61be2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -"1.6.0.0" +"2.0.0-b1" diff --git a/compat.h b/compat.h index 21f4200..c03ebec 100644 --- a/compat.h +++ b/compat.h @@ -1,5 +1,5 @@ /* $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 */ #ifndef __compat_h_included @@ -587,6 +587,8 @@ # endif #endif +#define F_thread "%lu" + /* Cygwin 1.3.22 has the prototypes, but not the type... */ #ifndef HAVE_TYPE_STAT64 # undef HAVE_STAT64 diff --git a/config.h.in b/config.h.in index 1dabea2..37a23d6 100644 --- a/config.h.in +++ b/config.h.in @@ -444,6 +444,8 @@ #undef HAVE_PROC_DIR_FD #undef WITH_HELP +#undef WITH_NOP +#undef WITH_TEST #undef WITH_STDIO #undef WITH_FDNUM #undef WITH_FILE @@ -461,6 +463,8 @@ #undef WITH_LISTEN #undef WITH_SOCKS4 #undef WITH_SOCKS4A +#define WITH_SOCKS5 1 +#define WITH_SOCKS4_SERVER 1 #undef WITH_PROXY #undef WITH_EXEC #undef WITH_SYSTEM diff --git a/configure.in b/configure.in index bf51c6a..4a32b71 100644 --- a/configure.in +++ b/configure.in @@ -90,6 +90,22 @@ AC_ARG_ENABLE(help, [ --disable-help disable help], esac], [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_ARG_ENABLE(stdio, [ --disable-stdio disable STDIO support], [case "$enableval" in diff --git a/doc/socat.1 b/doc/socat.1 index 3be5004..86443bf 100644 --- a/doc/socat.1 +++ b/doc/socat.1 @@ -1,11 +1,17 @@ -.TH "socat" "1" "March 2007" "socat" "" +.TH "socat" "1" "July 2006" "socat" "" .PP .PP .SH "NAME" socat \- Multipurpose relay (SOcket CAT) .PP .SH "SYNOPSIS" -\f(CWsocat [options]
\fP +\f(CWsocat [options] \fP +.br +\f(CWsocat [options] \fP +.br +\f(CWsocat [options] \&.\&.\fP +.br +\f(CWsocat [options] \&.\&. -- \&.\&.\fP .br \f(CWsocat -V\fP .br @@ -142,7 +148,7 @@ nothing has happened for [timeval] seconds Useful with protocols like UDP that cannot transfer EOF\&. .IP "\fB\f(CW-u\fP\fP" 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" Uses unidirectional mode in reverse direction\&. The first address is only 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 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 -\f(CWsocketpair()\fP per default\&. (example) +\f(CWsocketpair()\fP per default\&. .br Option groups: FD,SOCKET,EXEC,FORK,TERMIOS .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 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 Option groups: FD,REG,SOCKET,NAMED,OPEN .br @@ -315,7 +321,9 @@ Option groups: FD,SOCKET,IP4,IP6 .br Useful options: pf, -ttl +ttl, +broadcast +.br See also: IP4-SENDTO, IP6-SENDTO, @@ -334,52 +342,6 @@ Like IP-SENDTO, but always uses IPv6\&. Option groups: FD,SOCKET,IP6 .br .IP -.IP "\fB\f(CWIP-DATAGRAM:
:\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::\fP\fP" -Like IP-DATAGRAM, but always uses IPv4\&. -(example) -.br -Option groups: FD, SOCKET, -IP4, RANGE -.br -.IP "\fB\f(CWIP6-DATAGRAM::\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:\fP\fP" Opens a raw IP socket of \&. 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\&. @@ -449,8 +411,7 @@ Option groups: FD,SOCKET,IP6,RANGE .br .IP .IP "\fB\f(CWOPEN:\fP\fP" -Opens using the \f(CWopen()\fP system call -(example)\&. +Opens using the \f(CWopen()\fP system call\&. This operation fails on UNIX domain sockets\&. .br Note: This address type is rarly useful in bidirectional mode\&. @@ -510,9 +471,11 @@ connection is accepted, this address behaves as SSL server\&. .br Note: You probably want to use the certificate option with this address\&. .br -NOTE: The client certificate is only checked for validity against -cafile or capath, -but not for match with the client\'s name or its IP address! +NOTE: Without verify option, the client certificate is +not checked\&. Even with verify option, the client +certificate is only checked for validity against cafile +or capath, but not for match with the client\'s name or +its IP address! .br Option groups: FD,SOCKET,IP4,IP6,TCP,LISTEN,OPENSSL,CHILD,RANGE,RETRY .br @@ -596,11 +559,12 @@ retry .br See also: SOCKS, TCP .IP "\fB\f(CWPTY\fP\fP" +.IP "\fB\f(CWPTY:\fP\fP" 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\&. -(example)\&. If +may open the pty\'s slave side using it like a serial line or terminal\&. If 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 Option groups: FD,NAMED,PTY,TERMIOS .br @@ -618,7 +582,7 @@ PIPE, EXEC, SYSTEM .IP "\fB\f(CWREADLINE\fP\fP" 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, otherwise readline does not seem to work\&. .br @@ -635,7 +599,7 @@ Connects via [IP address] to [IPv4 address] on [TCP service], using socks version 4 protocol over IP version 4 or 6 depending on address specification, name resolution, or option -pf (example)\&. +pf\&. .br Option groups: FD,SOCKET,IP4,IP6,TCP,SOCKS4,RETRY .br @@ -743,7 +707,7 @@ TCP-LISTEN, UDP, UNIX-CONNECT .IP "\fB\f(CWTCP4::\fP\fP" -Like TCP, but only supports IPv4 protocol (example)\&. +Like TCP, but only supports IPv4 protocol\&. .br Option groups: FD,SOCKET,IP4,TCP,RETRY .br @@ -783,7 +747,7 @@ UNIX-LISTEN, OPENSSL-LISTEN .IP "\fB\f(CWTCP4-LISTEN:\fP\fP" Like TCP-LISTEN, but only supports IPv4 -protocol (example)\&. +protocol\&. .br Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4,TCP,RETRY .br @@ -796,23 +760,7 @@ ipv6only .br Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6,TCP,RETRY .br -.IP "\fB\f(CWTUN:/\fP\fP" -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 .IP "\fB\f(CWUDP::\fP\fP" Connects to [UDP service] on [IP address] using UDP/IP version 4 or 6 @@ -849,60 +797,14 @@ Like UDP, but only supports IPv6 protocol\&. .br Option groups: FD,SOCKET,IP6 .br -.IP "\fB\f(CWUDP-DATAGRAM:
:\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 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:
:\fP\fP" -Like UDP-DATAGRAM, but only supports IPv4 -protocol (example1, -example2)\&. -.br -Option groups: FD, SOCKET, -IP4, RANGE -.IP "\fB\f(CWUDP6-DATAGRAM:
:\fP\fP" -Like UDP-DATAGRAM, but only supports IPv6 -protocol\&. -.br -Option groups: FD,SOCKET, -IP6,RANGE +.IP .IP "\fB\f(CWUDP-LISTEN:\fP\fP" Waits for a UDP/IP packet arriving on [UDP service] and `connects\' back to sender\&. The accepted IP version is 4 or the one specified with option pf\&. Please note that, -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 +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 transported\&. Note that opening this address usually blocks until a client connects\&. .br @@ -931,14 +833,13 @@ protocol\&. .br Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6 .br +.IP .IP "\fB\f(CWUDP-SENDTO::\fP\fP" -Communicates with the specified peer socket, defined by [UDP -service] on +Communicates with the specified peer socket, defined by [UDP service] on [IP address], using UDP/IP version 4 or 6 depending on address specification, name resolution, or option -pf\&. It sends packets to and receives packets -from that peer socket only\&. -This address effectively implements a datagram client\&. +pf\&. It sends packets to and receives packets from that peer socket only\&. +This is effectively a datagram client\&. It works well with socat UDP-RECVFROM and UDP-RECV address peers\&. .br Option groups: FD,SOCKET,IP4,IP6 @@ -959,23 +860,19 @@ UDP-CONNECT, UDP-LISTEN, IP-SENDTO .IP "\fB\f(CWUDP4-SENDTO::\fP\fP" -Like UDP-SENDTO, but only supports IPv4 -protocol\&. +Like UDP-SENDTO, but only supports IPv4 protocol\&. .br Option groups: FD,SOCKET,IP4 .IP "\fB\f(CWUDP6-SENDTO::\fP\fP" -Like UDP-SENDTO, but only supports IPv6 -protocol\&. +Like UDP-SENDTO, but only supports IPv6 protocol\&. .br Option groups: FD,SOCKET,IP6 .IP .IP "\fB\f(CWUDP-RECVFROM:\fP\fP" -Creates a UDP socket on [UDP service] using -UDP/IP version 4 or 6 +Creates a UDP socket on [UDP service] using UDP/IP version 4 or 6 depending on option pf\&. 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 -option +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 allows a behaviour similar to typical UDP based servers like ntpd 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 [UDP service] using UDP/IP version 4 or 6 depending on option pf\&. 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 Option groups: FD,SOCKET,IP4,IP6,RANGE .br @@ -1050,9 +948,7 @@ if is not a UNIX domain socket, this is an error; if is a UNIX domain socket, but no process is listening, this is an error\&. .br -Option groups: FD,SOCKET, -NAMED,RETRY, -UNIX +Option groups: FD,SOCKET,NAMED,RETRY .br ) Useful options: @@ -1071,12 +967,9 @@ If exists and is a UNIX domain socket, binding to the address fails (use option unlink-early!)\&. 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 -this address is closed (but see option unlink-close) (example)\&. +this address is closed (but see option unlink-close)\&. .br -Option groups: FD,SOCKET, -NAMED,LISTEN, -CHILD,RETRY, -UNIX +Option groups: FD,SOCKET,NAMED,LISTEN,CHILD,RETRY .br Useful options: fork, @@ -1097,8 +990,7 @@ Communicates with the specified peer socket, defined by [] assuming it It sends packets to and receives packets from that peer socket only\&. It works well with socat UNIX-RECVFROM and UNIX-RECV address peers\&. .br -Option groups: FD,SOCKET, -NAMED,UNIX +Option groups: FD,SOCKET,NAMED .br Useful options: 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 address works well with socat UNIX-SENDTO address peers\&. .br -Option groups: FD,SOCKET, -NAMED,CHILD, -UNIX +Option groups: FD,SOCKET,NAMED,CHILD .br Useful options: fork @@ -1135,8 +1025,7 @@ Creates a UNIX domain datagram socket []\&. 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\&. It behaves similar to a syslog server\&. -Option groups: FD,SOCKET, -NAMED,UNIX +Option groups: FD,SOCKET,NAMED .br See also: UNIX-SENDTO, @@ -1145,14 +1034,13 @@ UNIX-LISTEN, UDP-RECV, IP-RECV .IP -.IP "\fB\f(CWUNIX-CLIENT:\fP\fP" +.IP "\fB\f(CWUNIX:\fP\fP" Communicates with the specified peer socket, defined by [] assuming it is a UNIX domain socket\&. It first tries to connect and, if that fails, assumes it is a datagram socket, thus supporting both types\&. .br -Option groups: FD,SOCKET, -NAMED,UNIX +Option groups: FD,SOCKET,NAMED .br Useful options: bind @@ -1161,19 +1049,6 @@ See also: UNIX-CONNECT, UNIX-SENDTO, GOPEN -.IP -.IP "\fB\f(CWABSTRACT-CONNECT:\fP\fP" -.IP "\fB\f(CWABSTRACT-LISTEN:\fP\fP" -.IP "\fB\f(CWABSTRACT-SENDTO:\fP\fP" -.IP "\fB\f(CWABSTRACT-RECVFROM:\fP\fP" -.IP "\fB\f(CWABSTRACT-RECV:\fP\fP" -.IP "\fB\f(CWABSTRACT-CLIENT:\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 .SH "ADDRESS OPTIONS" .PP @@ -1248,37 +1123,20 @@ internally handles this flag for the fds it controls, so in most cases there will be no need to apply this option\&. .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 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" -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, 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" 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 is locked by another process\&. .IP "\fB\f(CWflock-ex-nb\fP\fP" 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\&. .IP "\fB\f(CWflock-sh\fP\fP" 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" Sets a blocking lock on the file\&. Uses the setlk or flock mechanism 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=\fP\fP" Sets the (owner) of the stream\&. 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=\fP\fP" Always writes data to the actual end of file\&. 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 -(example)\&. +\fBsocat\fP uses the \f(CWO_APPEND\fP flag with the \f(CWopen()\fP system call\&. Otherwise, \fBsocat\fP applies the \f(CWfcntl(fd, F_SETFL, O_APPEND)\fP call\&. .IP "\fB\f(CWnonblock=\fP\fP" 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\&. .br 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 .br .PP @@ -1432,7 +1276,7 @@ E\&.g\&., option `creat\' sets the \f(CWO_CREAT\fP flag\&. See also options append and nonblock\&. .IP "\fB\f(CWcreat=\fP\fP" -Creates the file if it does not exist (example)\&. +Creates the file if it does not exist\&. .IP "\fB\f(CWdsync=\fP\fP" Blocks \f(CWwrite()\fP calls until metainfo is physically written to media\&. .IP "\fB\f(CWexcl=\fP\fP" @@ -1513,7 +1357,7 @@ option FORK, these options apply to the child processes instead of the main socat process\&. .IP "\fB\f(CWchroot=\fP\fP" Performs a \f(CWchroot()\fP operation to -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=\fP\fP" Performs a \f(CWchroot()\fP operation to before opening the address\&. This call might require root privilege\&. @@ -1531,11 +1375,11 @@ Changes the (owner) of the process before opening the address\&. This call might require root privilege\&. .IP "\fB\f(CWsu=\fP\fP" Changes the (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=\fP\fP" Short name for \fB\f(CWsubstuser-delayed\fP\fP\&. Changes the -(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 \f(CWchroot()\fP\&. This call might require root privilege\&. .IP "\fB\f(CWsetpgid=\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 process group\&. .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 .br .PP @@ -1552,7 +1396,7 @@ Makes the process the leader of a new session (example)\&. .PP These options apply to the readline address type\&. .IP "\fB\f(CWhistory=\fP\fP" -Reads and writes history from/to (example)\&. +Reads and writes history from/to \&. .IP "\fB\f(CWnoprompt\fP\fP" 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 @@ -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 typed\&. The pattern is a regular expression, e\&.g\&. "^[Pp]assword:\&.*$" or "([Uu]ser:|[Pp]assword:)"\&. See regex(7) for details\&. -(example) .IP "\fB\f(CWprompt=\fP\fP" Passes the string as prompt to the readline function\&. readline prints this 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\&. .IP "\fB\f(CWcrnl\fP\fP" 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\&. .IP "\fB\f(CWignoreeof\fP\fP" 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=\fP\fP" \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)\&. @@ -1610,7 +1453,7 @@ These options are intended for all kinds of sockets, e\&.g\&. IP or UNIX domain\ .IP "\fB\f(CWbind=\fP\fP" Binds the socket to the given socket address using the \f(CWbind()\fP system call\&. The form of 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 \&. .IP "\fB\f(CWconnect-timeout=\fP\fP" Abort the connection attempt after [timeval] @@ -1653,7 +1496,7 @@ the socket layer will pass the buffered data to \fBsocat\fP\&. Sets the receive timeout [timeval]\&. .IP "\fB\f(CWreuseaddr\fP\fP" 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=\fP\fP" Sets the size of the send buffer after the \f(CWsocket()\fP call to [int]\&. @@ -1676,14 +1519,6 @@ something like "ip4" or "ip6"\&. .PP .br .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 .PP 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" Takes 0, 1, 2 to never, want, or always use path MTU discover on this socket\&. -.IP "\fB\f(CWip-add-membership=\fP\fP" -.IP "\fB\f(CWip-add-membership=\fP\fP" -.IP "\fB\f(CWip-add-membership=\fP\fP" -.IP "\fB\f(CWip-add-membership=\fP\fP" -.IP "\fB\f(CWip-add-membership=\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=\fP\fP) -Specifies hostname or address of the network interface to be used for -multicast traffic\&. -dif(\fB\f(CWip-multicast-loop=\fP\fP) -Specifies if outgoing multicast traffic should loop back to the interface\&. -dif(\fB\f(CWip-multicast-ttl=\fP\fP) -Sets the TTL used for outgoing multicast traffic\&. Default is 1\&. .IP "\fB\f(CWres-debug\fP\fP" .IP "\fB\f(CWres-aaonly\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 .IP "\fB\f(CWmss=\fP\fP" Sets the MSS (maximum segment size) after the \f(CWsocket()\fP call to [int]\&. This -value is then proposed to the peer with the SYN or SYN/ACK packet -(example)\&. +value is then proposed to the peer with the SYN or SYN/ACK packet\&. .IP "\fB\f(CWmss-late=\fP\fP" Sets the MSS of the socket after connection has been established to [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 using an extra \f(CWbind()\fP call\&. 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" Outgoing (client) TCP and UDP connections with this option use 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 \&. .IP "\fB\f(CWsocksuser=\fP\fP" Sends the [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 .br .PP @@ -1877,20 +1691,19 @@ server unencrypted (base64 encoded) and might be sniffed\&. .IP "\fB\f(CWresolve\fP\fP" Per default, socat sends to the proxy a CONNECT request containing the target hostname\&. With this option, socat resolves the hostname locally and -sends the IP address\&. Please note that, according to RFC 2396, only name -resolution to IPv4 addresses is implemented\&. +sends the IP address\&. .PP .br .PP \fI\fBRANGE option group\fP\fP .PP -These options check if a connecting client should be granted access\&. They can -be applied to listening and receiving network sockets\&. tcp-wrappers options -fall into this group\&. +These options check if a connecting client is granted access\&. They can be +applied to listening and receiving network sockets\&. tcp-wrappers options fall +into this group\&. .IP "\fB\f(CWrange=\fP\fP" After accepting a connection, tests if the peer is within \fIrange\fP\&. For -IPv4 addresses, address-range takes the form address/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]\&. +IPv4 addresses, address-range takes the form ww\&.xx\&.yy\&.zz/bits, e\&.g\&. +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 listening/receiving\&. .IP "\fB\f(CWtcpwrap[=]\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 /etc/hosts\&.allow and /etc/hosts\&.deny per default, see "man 5 hosts_access" for more information\&. The optional (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 both tcpwrap and range options are applied to an address, both 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" After establishing a connection, handles its channel in a child process and 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 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 @@ -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 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 -compliant (example)\&. +compliant\&. .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" 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=\fP\fP" Assigns the sub processes input channel to its file descriptor 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=\fP\fP" Assigns the sub processes output channel to its file descriptor 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" 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\&. @@ -2033,12 +1846,12 @@ Note: On some operating systems, these options may not be available\&. Use ispeed or ospeed instead\&. .IP "\fB\f(CWecho=\fP\fP" -Enables or disables local echo (example)\&. +Enables or disables local echo\&. .IP "\fB\f(CWicanon=\fP\fP" Sets or clears canonical mode, enabling line buffering and some special characters\&. .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=\fP\fP" Ignores or interpretes the BREAK character (e\&.g\&., ^C) .IP "\fB\f(CWbrkint=\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 unpredictable names, making it difficult to directly access the socat 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 -(example)\&. +point in the file hierarchy that helps him to access the actual pty\&. Beginning with \fBsocat\fP version 1\&.4\&.3, the symbolic link is removed when the address is closed (but see option unlink-close)\&. .IP "\fB\f(CWwait-slave\fP\fP" @@ -2233,8 +2045,9 @@ this option is not provided\&. .IP "\f(CWTLSv1\fP" Select TLS protocol version 1\&. .IP "\fB\f(CWverify=\fP\fP" -Controls check of the peer\'s certificate\&. Default is 1 (true)\&. Disabling -verify might open your socket for everyone, making the encryption useless! +Controls check of the peer\'s certificate\&. Default is 1 (true) for client and +0 (false) for server addresses\&. Disabling verify might open your socket for +everyone! .IP "\fB\f(CWcert=\fP\fP" Specifies the file with the certificate and private key for authentication\&. The certificate must be in OpenSSL format (*\&.pem)\&. @@ -2295,61 +2108,6 @@ Performs an unlimited number of retry attempts\&. .PP .br .PP -\fI\fBTUN option group\fP\fP -.PP -Options that control Linux TUN/TAP interface device addresses\&. -.PP -.IP "\fB\f(CWtun-device=\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=\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" .PP This section explains the different data types that address parameters and @@ -2491,7 +2249,7 @@ second connection\&. \.LP \.nf \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 \.fi .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 prompts\&. .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 Generates a pseudo terminal 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 should establish connections to host www\&.domain\&.org on port 22 then\&. .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 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 "\fB\f(CWsocat - tcp:www\&.blackhat\&.org:31337,readbytes=1000\fP\fP" .IP -connects to an unknown service and prevents 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)\&. +connect to an unknown service and prevent being flooded\&. .IP .PP .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 system\&. .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 standard specifications available on the Internet for free\&. .PP .SH "VERSION" .PP -This man page describes version 1\&.6\&.0 of \fBsocat\fP\&. +This man page describes version 1\&.5\&.0 of \fBsocat\fP\&. .PP .SH "BUGS" .PP diff --git a/doc/socat.html b/doc/socat.html index 47e02fb..b18097e 100644 --- a/doc/socat.html +++ b/doc/socat.html @@ -24,7 +24,7 @@

socat

socat

-

March 2007

+

July 2006

@@ -54,7 +54,10 @@

SYNOPSIS

-socat [options] <address> <address>
+socat [options] <right-address>
+socat [options] <left-address> <right-address>
+socat [options] <left-address> <right-address> ..
+socat [options] <left-addresses> .. -- <right-address> ..
socat -V
socat -h[h[h]] | -?[?[?]]
filan
@@ -177,7 +180,7 @@ program. They have nothing to do with so called Useful with protocols like UDP that cannot transfer EOF.

-u
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.

-U
Uses unidirectional mode in reverse direction. The first address is only used for writing, and the second address is only used for reading. @@ -279,7 +282,7 @@ parameters, and semantics. $PATH apply. After successful program start, socat writes data to stdin of the process and reads from its stdout using a UNIX domain socket generated by - socketpair() per default. (example)
+ socketpair() per default.
Option groups: FD,SOCKET,EXEC,FORK,TERMIOS
Useful options: path, @@ -316,7 +319,7 @@ parameters, and semantics. If the entry is not a socket, socat opens it applying the O_APPEND flag. If it does not exist, it is opened with flag - O_CREAT as a regular file (example).
+ O_CREAT as a regular file.
Option groups: FD,REG,SOCKET,NAMED,OPEN
See also: OPEN, @@ -332,7 +335,8 @@ parameters, and semantics. Option groups: FD,SOCKET,IP4,IP6
Useful options: pf, - ttl + ttl, + broadcast
See also: IP4-SENDTO, IP6-SENDTO, @@ -346,44 +350,6 @@ parameters, and semantics.

IP6-SENDTO:<host>:<protocol>
Like IP-SENDTO, but always uses IPv6.
Option groups: FD,SOCKET,IP6
-

IP-DATAGRAM:<address>:<protocol>
- 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.
- Option groups: FD, SOCKET, - IP4, IP6, RANGE
- Useful options: - range, - tcpwrap, - broadcast, - ip-multicast-loop, - ip-multicast-ttl, - ip-multicast-if, - ip-add-membership, - ttl, - tos, - bind, - pf
- See also: - IP4-DATAGRAM, - IP6-DATAGRAM, - IP-SENDTO, - IP-RECVFROM, - IP-RECV, - UDP-DATAGRAM -

IP4-DATAGRAM:<host>:<protocol>
- Like IP-DATAGRAM, but always uses IPv4. - (example)
- Option groups: FD, SOCKET, - IP4, RANGE
-

IP6-DATAGRAM:<host>:<protocol>
- Like IP-DATAGRAM, but always uses IPv6. Please - note that IPv6 does not know broadcasts.
- Option groups: FD, SOCKET, - IP6, RANGE

IP-RECVFROM:<protocol>
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. @@ -398,7 +364,7 @@ parameters, and semantics. fork, range, ttl, - broadcast
+ broadcast
See also: IP4-RECVFROM, IP6-RECVFROM, @@ -437,8 +403,7 @@ parameters, and semantics. Like IP-RECV, but always uses IPv6.
Option groups: FD,SOCKET,IP6,RANGE

OPEN:<filename>
- Opens <filename> using the open() system call - (example). + Opens <filename> using the open() system call. This operation fails on UNIX domain sockets.
Note: This address type is rarly useful in bidirectional mode.
Option groups: FD,REG,NAMED,OPEN
@@ -488,9 +453,11 @@ parameters, and semantics. pf. When a connection is accepted, this address behaves as SSL server.
Note: You probably want to use the certificate option with this address.
- NOTE: The client certificate is only checked for validity against - cafile or capath, - but not for match with the client's name or its IP address!
+ NOTE: Without verify option, the client certificate is + not checked. Even with verify option, the client + certificate is only checked for validity against cafile + or capath, but not for match with the client's name or + its IP address!
Option groups: FD,SOCKET,IP4,IP6,TCP,LISTEN,OPENSSL,CHILD,RANGE,RETRY
Useful options: pf, @@ -560,11 +527,12 @@ parameters, and semantics. retry
See also: SOCKS, TCP

PTY
+

PTY:<symlink>
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. - (example). If + may open the pty's slave side using it like a serial line or terminal. If 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.
Option groups: FD,NAMED,PTY,TERMIOS
Useful options: link, @@ -579,7 +547,7 @@ parameters, and semantics. EXEC, SYSTEM

READLINE
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, otherwise readline does not seem to work.
Option groups: FD,READLINE,TERMIOS
@@ -593,7 +561,7 @@ parameters, and semantics. to <host> [IPv4 address] on <port> [TCP service], using socks version 4 protocol over IP version 4 or 6 depending on address specification, name resolution, or option - pf (example).
+ pf.
Option groups: FD,SOCKET,IP4,IP6,TCP,SOCKS4,RETRY
Useful options: socksuser, @@ -680,7 +648,7 @@ parameters, and semantics. UDP, UNIX-CONNECT

TCP4:<host>:<port>
- Like TCP, but only supports IPv4 protocol (example).
+ Like TCP, but only supports IPv4 protocol.
Option groups: FD,SOCKET,IP4,TCP,RETRY

TCP6:<host>:<port>
Like TCP, but only supports IPv6 protocol.
@@ -713,7 +681,7 @@ parameters, and semantics. OPENSSL-LISTEN

TCP4-LISTEN:<port>
Like TCP-LISTEN, but only supports IPv4 - protocol (example).
+ protocol.
Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4,TCP,RETRY

TCP6-LISTEN:<port>
Like TCP-LISTEN, but only supports IPv6 @@ -721,22 +689,7 @@ parameters, and semantics. Additional useful option: ipv6only
Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6,TCP,RETRY
-

TUN:<if-addr>/<bits>
- 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 /dev/net/tun. -
- Option groups: FD,NAMED,OPEN,TUN
- Useful options: - iff-up, - tun-device, - tun-name, - tun-type, - iff-no-pi
- See also: - ip-recv -

UDP:<host>:<port>
+

UDP:<host>:<port>
Connects to <port> [UDP service] on <host> [IP address] using UDP/IP version 4 or 6 depending on address specification, name resolution, or option @@ -764,55 +717,13 @@ parameters, and semantics.

UDP6:<host>:<port>
Like UDP, but only supports IPv6 protocol.
Option groups: FD,SOCKET,IP6
-

UDP-DATAGRAM:<address>:<port>
- 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.
- Option groups: FD,SOCKET,IP4,IP6,RANGE
- Useful options: - range, - tcpwrap, - broadcast, - ip-multicast-loop, - ip-multicast-ttl, - ip-multicast-if, - ip-add-membership, - ttl, - tos, - bind, - sourceport, - pf
- See also: - UDP4-DATAGRAM, - UDP6-DATAGRAM, - UDP-SENDTO, - UDP-RECVFROM, - UDP-RECV, - UDP-CONNECT, - UDP-LISTEN, - IP-DATAGRAM -

UDP4-DATAGRAM:<address>:<port>
- Like UDP-DATAGRAM, but only supports IPv4 - protocol (example1, - example2).
- Option groups: FD, SOCKET, - IP4, RANGE -

UDP6-DATAGRAM:<address>:<port>
- Like UDP-DATAGRAM, but only supports IPv6 - protocol.
- Option groups: FD,SOCKET, - IP6,RANGE -

UDP-LISTEN:<port>
+

UDP-LISTEN:<port>
Waits for a UDP/IP packet arriving on <port> [UDP service] and `connects' back to sender. The accepted IP version is 4 or the one specified with option pf. Please note that, - 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 + 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 transported. Note that opening this address usually blocks until a client connects.
Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4,IP6
@@ -834,14 +745,12 @@ parameters, and semantics. Like UDP-LISTEN, but only support IPv6 protocol.
Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6
-

UDP-SENDTO:<host>:<port>
- Communicates with the specified peer socket, defined by <port> [UDP - service] on +

UDP-SENDTO:<host>:<port>
+ Communicates with the specified peer socket, defined by <port> [UDP service] on <host> [IP address], using UDP/IP version 4 or 6 depending on address specification, name resolution, or option - pf. It sends packets to and receives packets - from that peer socket only. - This address effectively implements a datagram client. + pf. It sends packets to and receives packets from that peer socket only. + This is effectively a datagram client. It works well with socat UDP-RECVFROM and UDP-RECV address peers.
Option groups: FD,SOCKET,IP4,IP6
Useful options: @@ -859,20 +768,16 @@ parameters, and semantics. UDP-LISTEN, IP-SENDTO

UDP4-SENDTO:<host>:<port>
- Like UDP-SENDTO, but only supports IPv4 - protocol.
+ Like UDP-SENDTO, but only supports IPv4 protocol.
Option groups: FD,SOCKET,IP4

UDP6-SENDTO:<host>:<port>
- Like UDP-SENDTO, but only supports IPv6 - protocol.
+ Like UDP-SENDTO, but only supports IPv6 protocol.
Option groups: FD,SOCKET,IP6

UDP-RECVFROM:<port>
- 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. 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 - option + 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 allows a behaviour similar to typical UDP based servers like ntpd or named. This address works well with socat SENDTO address peers.
@@ -903,7 +808,8 @@ parameters, and semantics. Creates a UDP socket on <port> [UDP service] using UDP/IP version 4 or 6 depending on option pf. 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.
Option groups: FD,SOCKET,IP4,IP6,RANGE
Useful options: fork, @@ -934,9 +840,7 @@ parameters, and semantics. 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 an error.
- Option groups: FD,SOCKET, - NAMED,RETRY, - UNIX
) + Option groups: FD,SOCKET,NAMED,RETRY
) Useful options: bind
See also: @@ -951,11 +855,8 @@ parameters, and semantics. fails (use option unlink-early!). 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 - this address is closed (but see option unlink-close) (example).
- Option groups: FD,SOCKET, - NAMED,LISTEN, - CHILD,RETRY, - UNIX
+ this address is closed (but see option unlink-close).
+ Option groups: FD,SOCKET,NAMED,LISTEN,CHILD,RETRY
Useful options: fork, umask, @@ -972,8 +873,7 @@ parameters, and semantics. Communicates with the specified peer socket, defined by [<filename>] assuming it is a UNIX domain datagram socket. It sends packets to and receives packets from that peer socket only. It works well with socat UNIX-RECVFROM and UNIX-RECV address peers.
- Option groups: FD,SOCKET, - NAMED,UNIX
+ Option groups: FD,SOCKET,NAMED
Useful options: bind
See also: @@ -987,9 +887,7 @@ parameters, and semantics. 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 address works well with socat UNIX-SENDTO address peers.
- Option groups: FD,SOCKET, - NAMED,CHILD, - UNIX
+ Option groups: FD,SOCKET,NAMED,CHILD
Useful options: fork
See also: @@ -1003,39 +901,25 @@ parameters, and semantics. 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. It behaves similar to a syslog server. - Option groups: FD,SOCKET, - NAMED,UNIX
+ Option groups: FD,SOCKET,NAMED
See also: UNIX-SENDTO, UNIX-RECVFROM, UNIX-LISTEN, UDP-RECV, IP-RECV -

UNIX-CLIENT:<filename>
+

UNIX:<filename>
Communicates with the specified peer socket, defined by [<filename>] assuming it is a UNIX domain socket. It first tries to connect and, if that fails, assumes it is a datagram socket, thus supporting both types.
- Option groups: FD,SOCKET, - NAMED,UNIX
+ Option groups: FD,SOCKET,NAMED
Useful options: bind
See also: UNIX-CONNECT, UNIX-SENDTO, GOPEN -

ABSTRACT-CONNECT:<string>
-

ABSTRACT-LISTEN:<string>
-

ABSTRACT-SENDTO:<string>
-

ABSTRACT-RECVFROM:<string>
-

ABSTRACT-RECV:<string>
-

ABSTRACT-CLIENT:<string>
- 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 "\0" 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.

ADDRESS OPTIONS

@@ -1101,38 +985,21 @@ which mechanism is used. The second, non-fd based mechanism is prioritized. internally handles this flag for the fds it controls, so in most cases there will be no need to apply this option. -

setlk
- Tries to set a discretionary write lock to the whole file using the fcntl(fd, +

setlk
+ Tries to set a discretionary lock to the whole file using the fcntl(fd, F_SETLK, ...) system call. If the file is already locked, this call results 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. -

setlkw
- Tries to set a discretionary waiting write lock to the whole file using the +

setlkw
+ Tries to set a discretionary waiting lock to the whole file using the fcntl(fd, F_SETLKW, ...) system call. If the file is already locked, this call blocks. - See option setlk for information about making this - lock mandatory. -

setlk-rd
- Tries to set a discretionary read lock to the whole file using the fcntl(fd, - F_SETLK, ...) 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. -

setlkw-rd
- Tries to set a discretionary waiting read lock to the whole file using the - fcntl(fd, F_SETLKW, ...) system call. If the file is already write - locked, this call blocks. - See option setlk for information about making this - lock mandatory.

flock-ex
Tries to set a blocking exclusive advisory lock to the file using the flock(fd, LOCK_EX) system call. Socat hangs in this call if the file is locked by another process.

flock-ex-nb
Tries to set a nonblocking exclusive advisory lock to the file using the - flock(fd, LOCK_EX|LOCK_NB) system call. If the file is already locked, + flock(fd, LOCK_EX) system call. If the file is already locked, this option results in an error.

flock-sh
Tries to set a blocking shared advisory lock to the file using the @@ -1145,7 +1012,7 @@ which mechanism is used. The second, non-fd based mechanism is prioritized.

lock
Sets a blocking lock on the file. Uses the setlk or flock mechanism depending on availability on the particular platform. If both are available, - the POSIX variant (setlkw) is used. + the POSIX variant (setlkw) is selected.

user=<user>
Sets the <user> (owner) of the stream. If the address is member of the NAMED option group, @@ -1190,8 +1057,7 @@ which mechanism is used. The second, non-fd based mechanism is prioritized.

append=<bool>
Always writes data to the actual end of file. If the address is member of the OPEN option group, - socat uses the O_APPEND flag with the open() system call - (example). + socat uses the O_APPEND flag with the open() system call. Otherwise, socat applies the fcntl(fd, F_SETFL, O_APPEND) call.

nonblock=<bool>
Tries to open or use file in nonblocking mode. Its only effects are that the @@ -1217,17 +1083,6 @@ which mechanism is used. The second, non-fd based mechanism is prioritized. when socat is used as a high volume server or proxy where clients often abort the connection.
This option is experimental. -

end-close
- 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).
- Normally, socket connections will be ended with shutdown(2) which - terminates the socket even if it is shared by multiple processes. - close(2) "unlinks" the socket from the process but keeps it active as - long as there are still links from other processes.
- 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.


NAMED option group @@ -1280,7 +1135,7 @@ See also options append and nonblock.

creat=<bool>
- Creates the file if it does not exist (example). + Creates the file if it does not exist.

dsync=<bool>
Blocks write() calls until metainfo is physically written to media.

excl=<bool>
@@ -1363,7 +1218,7 @@ these options apply to the child processes instead of the main socat process.

chroot=<directory>
Performs a chroot() operation to <directory> - after processing the address (example). This call might require root privilege. + after processing the address. This call might require root privilege.

chroot-early=<directory>
Performs a chroot() operation to <directory> before opening the address. This call might require root privilege. @@ -1381,11 +1236,11 @@ these options apply to the child processes instead of the main socat process. the address. This call might require root privilege.

su=<user>
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.

su-d=<user>
Short name for substuser-delayed. 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 before a possible chroot(). This call might require root privilege.

setpgid=<pid_t>
@@ -1394,14 +1249,14 @@ these options apply to the child processes instead of the main socat process. is given, or if the value is 0 or 1, the process becomes leader of a new process group.

setsid
- Makes the process the leader of a new session (example). + Makes the process the leader of a new session.


READLINE option group

These options apply to the readline address type.

history=<filename>
- Reads and writes history from/to <filename> (example). + Reads and writes history from/to <filename>.

noprompt
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 @@ -1415,7 +1270,6 @@ these options apply to the child processes instead of the main socat process. after the lastest newline character and before an input character was typed. The pattern is a regular expression, e.g. "^[Pp]assword:.*$" or "([Uu]ser:|[Pp]assword:)". See regex(7) for details. - (example)

prompt=<string>
Passes the string as prompt to the readline function. readline prints this prompt when stepping through the history. If this string matches a constant @@ -1434,11 +1288,11 @@ but not to protocol data used by addresses like ('\r', 0x0d) when writing/reading on this channel.

crnl
Converts the default line termination character NL ('\n', 0x0a) to/from CRNL - ("\r\n", 0x0d0a) when writing/reading on this channel (example). + ("\r\n", 0x0d0a) when writing/reading on this channel. Note: socat simply strips all CR characters.

ignoreeof
When EOF occurs on this channel, socat ignores it and tries to read more - data (like "tail -f") (example). + data (like "tail -f").

readbytes=<bytes>
socat reads only so many bytes from this address (the address provides only so many bytes for transfer and pretends to be at EOF afterwards). @@ -1457,7 +1311,7 @@ but not to protocol data used by addresses like

bind=<sockname>
Binds the socket to the given socket address using the bind() system 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>.

connect-timeout=<seconds>
Abort the connection attempt after <seconds> [timeval] @@ -1465,7 +1319,7 @@ but not to protocol data used by addresses like

interface=<interface>
Binds the socket to the given <interface>. This option might require root privilege. -

broadcast
+

broadcast
For datagram sockets, allows sending to broadcast addresses and receiving packets addressed to broadcast addresses.

bsdcompat
@@ -1501,7 +1355,7 @@ but not to protocol data used by addresses like Sets the receive timeout [timeval].

reuseaddr
Allows other sockets to bind to an address even if parts of it (e.g. the - local port) are already in use by socat (example). + local port) are already in use by socat.

sndbuf=<bytes>
Sets the size of the send buffer after the socket() call to <bytes> [int]. @@ -1544,14 +1398,6 @@ but not to protocol data used by addresses like something like "ip4" or "ip6".


-

UNIX option group -

These options apply to UNIX domain based addresses. -

-

unix-tightsocklen=[0|1]
- On socket operations, pass a socket address length that does not include the - whole struct sockaddr_un record but (besides other components) only - the relevant part of the filename or abstract string. Default is 1. -

IP4 and IP6 option groups

These options can be used with IPv4 and IPv6 based sockets. @@ -1585,29 +1431,6 @@ but not to protocol data used by addresses like - -

ip-add-membership=<multicast-address:interface-address>
-

ip-add-membership=<multicast-address:interface-name>
-

ip-add-membership=<multicast-address:interface-index>
-

ip-add-membership=<multicast-address:interface-address:interface-name>
-

ip-add-membership=<multicast-address:interface-address:interface-index>
- 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 struct mreqn (Linux).
- The indices of active network interfaces can be shown using the utility - procan. - -dif(ip-multicast-if=<hostname>) - Specifies hostname or address of the network interface to be used for - multicast traffic. - -dif(ip-multicast-loop=<bool>) - Specifies if outgoing multicast traffic should loop back to the interface. - -dif(ip-multicast-ttl=<byte>) - Sets the TTL used for outgoing multicast traffic. Default is 1.

res-debug

res-aaonly

res-usevc
@@ -1656,8 +1479,7 @@ sockets.

mss=<bytes>
Sets the MSS (maximum segment size) after the socket() call to <bytes> [int]. This - value is then proposed to the peer with the SYN or SYN/ACK packet - (example). + value is then proposed to the peer with the SYN or SYN/ACK packet.

mss-late=<bytes>
Sets the MSS of the socket after connection has been established to <bytes> [int]. @@ -1709,7 +1531,7 @@ thus can be used with UDP and TCP, client and server addresses. For outgoing (client) TCP and UDP connections, it sets the source <port> using an extra bind() call. 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.

lowport
Outgoing (client) TCP and UDP connections with this option use an unused random source port between 640 and 1023 incl. On UNIX class operating @@ -1728,7 +1550,7 @@ thus can be used with UDP and TCP, client and server addresses. port with <TCP service>.

socksuser=<user>
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).


HTTP option group @@ -1753,19 +1575,18 @@ currently implemented is proxy-connec

resolve
Per default, socat sends to the proxy a CONNECT request containing the target hostname. With this option, socat resolves the hostname locally and - sends the IP address. Please note that, according to RFC 2396, only name - resolution to IPv4 addresses is implemented. + sends the IP address.


RANGE option group -

These options check if a connecting client should be granted access. They can -be applied to listening and receiving network sockets. tcp-wrappers options -fall into this group. +

These options check if a connecting client is granted access. They can be +applied to listening and receiving network sockets. tcp-wrappers options fall +into this group.

range=<address-range>
After accepting a connection, tests if the peer is within range. For - IPv4 addresses, address-range takes the form address/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]. + IPv4 addresses, address-range takes the form ww.xx.yy.zz/bits, e.g. + 10.0.0.0/8; for IPv6, it is [ip6-address/bits], e.g. [::1/128]. If the client address does not match, socat issues a warning and keeps listening/receiving.

tcpwrap[=<name>]
@@ -1773,7 +1594,7 @@ fall into this group. 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" 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 both tcpwrap and range options are applied to an address, both conditions must be fulfilled to allow the connection. @@ -1801,7 +1622,7 @@ fall into this group.

fork
After establishing a connection, handles its channel in a child process and 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.
SSL-CONNECT and SSL-LISTEN differ in when they actually fork off the child: SSL-LISTEN forks before the SSL handshake, while SSL-CONNECT forks afterwards. @@ -1857,22 +1678,22 @@ socat process. Establishes communication with the sub process using a pseudo terminal 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 - compliant (example). + compliant.

ctty
- Makes the pty the controlling tty of the sub process (example). + Makes the pty the controlling tty of the sub process.

stderr
Directs stderr of the sub process to its output channel by making stderr a - dup() of stdout (example). + dup() of stdout.

fdin=<fdnum>
Assigns the sub processes input channel to its file descriptor <fdnum> instead of stdin (0). The program started from the subprocess has to use - this fd for reading data from socat (example). + this fd for reading data from socat.

fdout=<fdnum>
Assigns the sub processes output channel to its file descriptor <fdnum> instead of stdout (1). The program started from the subprocess has to use - this fd for writing data to socat (example). + this fd for writing data to socat.

sighup, sigint, sigquit
Has socat pass an eventual signal of this type to the sub process. If no address has this option, socat terminates on these signals. @@ -1896,12 +1717,12 @@ Note: On some operating systems, these options may not be available. Use ispeed or ospeed instead.

echo=<bool>
- Enables or disables local echo (example). + Enables or disables local echo.

icanon=<bool>
Sets or clears canonical mode, enabling line buffering and some special characters.

raw
- Sets raw mode, thus passing input and output almost unprocessed (example). + Sets raw mode, thus passing input and output almost unprocessed.

ignbrk=<bool>
Ignores or interpretes the BREAK character (e.g., ^C)

brkint=<bool>
@@ -2033,8 +1854,7 @@ type. to solve the problem that ptys are generated with more or less unpredictable names, making it difficult to directly access the socat 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 - (example). + point in the file hierarchy that helps him to access the actual pty. Beginning with socat version 1.4.3, the symbolic link is removed when the address is closed (but see option unlink-close).

wait-slave
@@ -2084,8 +1904,9 @@ type.

TLSv1
Select TLS protocol version 1.

verify=<bool>
- Controls check of the peer's certificate. Default is 1 (true). Disabling - verify might open your socket for everyone, making the encryption useless! + Controls check of the peer's certificate. Default is 1 (true) for client and + 0 (false) for server addresses. Disabling verify might open your socket for + everyone!

cert=<filename>
Specifies the file with the certificate and private key for authentication. The certificate must be in OpenSSL format (*.pem). @@ -2142,59 +1963,6 @@ attempts. Performs an unlimited number of retry attempts.


-

TUN option group -

Options that control Linux TUN/TAP interface device addresses. -

-

tun-device=<device-file>
- Instructs socat to take another path for the TUN clone device. Default is - /dev/net/tun. -

tun-name=<if-name>
- Gives the resulting network interface a specific name instead of the system - generated (tun0, tun1, etc.) -

tun-type=[tun|tap]
- 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. -

iff-no-pi
- 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. -

iff-up
- Sets the TUN network interface status UP. Strongly recommended. -

iff-broadcast
- Sets the BROADCAST flag of the TUN network interface. -

iff-debug
- Sets the DEBUG flag of the TUN network interface. -

iff-loopback
- Sets the LOOPBACK flag of the TUN network interface. -

iff-pointopoint
- Sets the POINTOPOINT flag of the TUN device. -

iff-notrailers
- Sets the NOTRAILERS flag of the TUN device. -

iff-running
- Sets the RUNNING flag of the TUN device. -

iff-noarp
- Sets the NOARP flag of the TUN device. -

iff-promisc
- Sets the PROMISC flag of the TUN device. -

iff-allmulti
- Sets the ALLMULTI flag of the TUN device. -

iff-master
- Sets the MASTER flag of the TUN device. -

iff-slave
- Sets the SLAVE flag of the TUN device. -

iff-multicast
- Sets the MULTICAST flag of the TUN device. -

iff-portsel
- Sets the PORTSEL flag of the TUN device. -

iff-automedia
- Sets the AUTOMEDIA flag of the TUN device. -

iff-dynamic
- Sets the DYNAMIC flag of the TUN device. -
-


DATA VALUES

@@ -2302,16 +2070,13 @@ address options can take.

EXAMPLES

-

-

socat - TCP4:www.domain.org:80
+

socat - TCP4:www.domain.org:80

Transfers data between STDIO (-) and a TCP4 connection to port 80 of host www.domain.org. This example results in an interactive connection similar to telnet or netcat. The stdin terminal parameters are not changed, so you may close the relay with ^D or abort it with ^C. -

- - +

@@ -2323,19 +2088,13 @@ bash like manner (READLINE) and use th prints messages about progress (-d -d). The port is specified by service name (www), and correct network line termination characters (crnl) instead of NL are used. -

-

socat TCP4-LISTEN:www TCP4:www.domain.org:www
+

socat TCP4-LISTEN:www TCP4:www.domain.org:www

Installs a simple TCP port forwarder. With TCP4-LISTEN it listens on local port "www" until a connection comes in, accepts it, then connects to the remote host (TCP4) and starts data transfer. It will not accept a second connection. -

- - - - - +

@@ -2354,13 +2113,7 @@ termination, even if some child sockets are not completely shut down. With -lmlocal2, socat logs to stderr until successfully reaching the accept loop. Further logging is directed to syslog with facility local2. -

- - - - - - +

@@ -2379,11 +2132,7 @@ the program /home/sandbox/bin/myscript. Socat myscript communicate via a pseudo tty (pty); myscript's stderr is redirected to stdout, so its error messages are transferred via socat to the connected client. -

- - - - +

@@ -2400,20 +2149,13 @@ mail body from stdin. Socat makes alias1 your local source addr (bind), cares for correct network line termination (crnl) and sends at most 512 data bytes per packet (mss). -

- - -

socat - /dev/ttyS0,raw,echo=0,crnl
+

socat - /dev/ttyS0,raw,echo=0,crnl

Opens an interactive connection via the serial line, e.g. for talking with a modem. raw and echo set ttyS0's terminal parameters to practicable values, crnl converts to correct newline characters. Consider using READLINE instead of `-'. -

- - - - +

@@ -2433,9 +2175,7 @@ a connection to the victims XWindow server and, if it does not require MIT cookies or Kerberos authentication, we can start work. Please note that there can only be one connection at a time, because TCP can establish only one session with a given set of addresses and ports. -

- -

socat -u /tmp/readdata,seek-end=0,ignoreeof -
+

socat -u /tmp/readdata,seek-end=0,ignoreeof -

This is an example for unidirectional data transfer (-u). Socat transfers data from file /tmp/readdata (implicit address GOPEN), starting @@ -2444,9 +2184,7 @@ reading at current end of file; use seek=0 seek option to first read the existing data) in a "tail -f" like mode (ignoreeof). The "file" might also be a listening UNIX domain socket (do not use a seek option then). -

- - +

@@ -2456,10 +2194,7 @@ might also be a listening UNIX domain socket (do not use a seek option then). ssh, makes it ssh's controlling tty (ctty), and makes this pty the owner of a new process group (setsid), so ssh accepts the password from socat. -

- - - +

@@ -2473,19 +2208,14 @@ Option reuseaddr allows immediate rest process.

-

-

socat READLINE,noecho='[Pp]assword:' EXEC:'ftp ftp.server.com',pty,setsid,ctty
+

socat READLINE,noecho='[Pp]assword:' EXEC:'ftp ftp.server.com',pty,setsid,ctty

Wraps a command line history (READLINE) around the EXEC'uted ftp client utility. This allows editing and reuse of FTP commands for relatively comfortable browsing through the ftp directory hierarchy. The password is echoed! pty is required to have ftp issue a prompt. Nevertheless, there may occur some confusion with the password and FTP prompts. -

- - - -(socat PTY,link=$HOME/dev/vmodem0,raw,echo=0,waitslave EXEC:'"ssh modemserver.us.org socat - /dev/ttyS0,nonblock,raw,echo=0"') +

socat PTY,link=$HOME/dev/vmodem0,raw,echo=0,waitslave exec:'"ssh modemserver.us.org socat - /dev/ttyS0,nonblock,raw,echo=0"'

Generates a pseudo terminal device (PTY) on the client that can be reached under the symbolic link $HOME/dev/vmodem0. @@ -2504,26 +2234,6 @@ through the proxy daemon listenin (proxyport) on host proxy, using the 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. -

-

socat - SSL:server:4443,cafile=server.crt,cert=client.pem
-

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.
-The first address ('-') can be replaced by almost any other socat address. -

-

socat SSL-LISTEN:4443,reuseaddr,pf=ip4,fork,cert=server.pem,cafile=client.crt PIPE
-

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.
-The second address ('PIPE') can be replaced by almost any other socat -address.
-For instructions on generating and distributing OpenSSL keys and certificates -see the additional socat docu socat-openssl.txt.

echo |socat -u - file:/tmp/bigfile,create,largefile,seek=100000000000

creates a 100GB sparse file; this requires a file system type that supports this (ext2, ext3, reiserfs, jfs; not minix, vfat). The operation of @@ -2540,41 +2250,7 @@ stderr (your terminal window). the executable /usr/bin/squid at offset 0x00074420 (this is a real world patch to make the squid executable from Cygwin run under Windows, actual per May 2004).

socat - tcp:www.blackhat.org:31337,readbytes=1000
-

connects to an unknown service and prevents being flooded. -

-

socat -U TCP:target:9999,end-close TCP-L:8888,reuseaddr,fork
-

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). -

-

socat - UDP4-DATAGRAM:192.168.1.0:123,sp=123,broadcast,range=192.168.1.0/24
-

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. -

-

socat - IP4-DATAGRAM:255.255.255.255:44,broadcast,range=10.0.0.0/8
-

sends a broadcast to the local network(s) using protocol 44. Accepts replies -from the private address range only. -

-

socat - UDP4-DATAGRAM:224.255.0.1:6666,bind=:6666,ip-add-membership=224.255.0.1:eth0
-

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. -

-

socat TCP:host2:4443 TUN:192.168.255.1/24,up
-

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). +

connect to an unknown service and prevent being flooded.

DIAGNOSTICS

@@ -2654,12 +2330,14 @@ with their free and portable development software and lots of other useful tools and libraries.

The Linux developers community (http://www.linux.org/) for providing a free, open source operating system. +

Sourceforge (http://www.sourceforge.net/) for providing a compile +farm with Solaris, FreeBSD, and MacOS X machines, making these ports possible.

The Open Group (http://www.unix-systems.org/) for making their standard specifications available on the Internet for free.

VERSION

-

This man page describes version 1.6.0 of socat. +

This man page describes version 1.5.0 of socat.

BUGS

diff --git a/error.c b/error.c index 3345979..0728515 100644 --- a/error.c +++ b/error.c @@ -176,8 +176,8 @@ void msg(int level, const char *format, ...) { result = gettimeofday(&now, NULL); if (result < 0) { /* invoking msg() might create endless recursion; by hand instead */ - sprintf(buff, "cannot read time: %s["F_pid"] E %s", - diagopts.progname, getpid(), strerror(errno)); + sprintf(buff, "cannot read time: %s["F_pid".%lu] E %s", + diagopts.progname, getpid(), (unsigned long)pthread_self(), strerror(errno)); _msg(LOG_ERR, buff, strstr(buff, " E "+1)); strcpy(buff, "unknown time "); bytes = 20; } else { @@ -215,7 +215,8 @@ void msg(int level, const char *format, ...) { if (diagopts.withhostname) { 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; syslp = bufp; *bufp++ = "DINWEF"[level]; diff --git a/ftp.sh b/ftp.sh index 91e768d..8489137 100755 --- a/ftp.sh +++ b/ftp.sh @@ -80,7 +80,7 @@ TMPDIR=$(if [ -x /bin/mktemp ]; then (umask 077; d=/tmp/$USER/FTPSH.$$; mkdir $d; echo $d) fi) 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=$! while ! [ -p "$TO" -a -p "$FROM" ]; do sleep 1; done exec 4>$TMPDIR/to 3<$TMPDIR/from diff --git a/nestlex.c b/nestlex.c index a9099ef..4cadd82 100644 --- a/nestlex.c +++ b/nestlex.c @@ -1,5 +1,5 @@ /* $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 */ /* 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 *nests[],/* list of strings that start nesting; every second one is matching end */ + bool dropspace, /* drop trailing space before end token */ bool dropquotes, /* drop the outermost quotes */ bool c_esc, /* solve C char escapes: \n \t \0 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 **nestx; /* loops over nest patterns */ char *out = *token; /* pointer into output token */ + char *lastnonspace = out; char c; int i; int result; @@ -46,7 +48,9 @@ int nestlex(const char **addr, /* input string; aft points to end token */ /* is this end of input string? */ if (*in == 0) { - + if (dropspace) { + out = lastnonspace; + } break; /* end of string */ } @@ -55,6 +59,9 @@ int nestlex(const char **addr, /* input string; aft points to end token */ while (*endx) { if (!strncmp(in, *endx, strlen(*endx))) { /* this end pattern matches */ + if (dropspace) { + out = lastnonspace; + } *addr = in; *token = out; return 0; @@ -83,7 +90,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */ result = nestlex(&in, &out, len, endnest, NULL/*hquotes*/, NULL/*squotes*/, NULL/*nests*/, - false, c_esc, html_esc); + false, false, c_esc, html_esc); if (result == 0 && dropquotes) { /* we strip this quote */ in += strlen(*quotx); @@ -101,6 +108,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */ } if (hquotes && *quotx != NULL) { /* there was a quote; string might continue with hard quote */ + lastnonspace = out; continue; } @@ -126,7 +134,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */ result = nestlex(&in, &out, len, endnest, hquotes, squotes, nests, - false, c_esc, html_esc); + false, false, c_esc, html_esc); if (result == 0 && dropquotes) { /* 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) { /* there was a soft quote; string might continue with any quote */ + lastnonspace = out; continue; } @@ -163,7 +172,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */ result = nestlex(&in, &out, len, endnest, hquotes, squotes, nests, - false, c_esc, html_esc); + false, false, c_esc, html_esc); if (result == 0) { /* copy endnest */ 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) { /* we handled a nested expression, continue loop */ + lastnonspace = out; continue; } @@ -216,6 +226,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */ *token = out; return -1; /* output overflow */ } + lastnonspace = out; continue; } @@ -227,6 +238,9 @@ int nestlex(const char **addr, /* input string; aft points to end token */ *token = out; return -1; /* output overflow */ } + if (!isspace(c)) { + lastnonspace = out; + } } /* never come here? */ @@ -235,3 +249,10 @@ int nestlex(const char **addr, /* input string; aft points to end token */ *token = out; return 0; /* OK */ } + +int skipsp(const char **text) { + while (isspace(**text)) { + ++(*text); + } + return 0; +} diff --git a/nestlex.h b/nestlex.h index af0828a..206ffde 100644 --- a/nestlex.h +++ b/nestlex.h @@ -1,5 +1,5 @@ /* $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 */ #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 *nests[],/* list of strings that start nesting; every second one is matching end */ + bool dropspace, /* drop trailing space before end token */ bool dropquotes, /* drop the outermost quotes */ bool c_esc, /* solve C char escapes: \n \t \0 etc */ bool html_esc /* solve HTML char escapes: %0d %08 etc */ ); +extern +int skipsp(const char **text); + #endif /* !defined(__nestlex_h_included) */ diff --git a/procan.c b/procan.c index b25efee..376b890 100644 --- a/procan.c +++ b/procan.c @@ -1,5 +1,5 @@ /* $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 */ /* the subroutine procan makes a "PROCess ANalysis". It gathers information diff --git a/socat.c b/socat.c index 1231694..5b93804 100644 --- a/socat.c +++ b/socat.c @@ -20,45 +20,25 @@ #include "filan.h" #include "xio.h" #include "xioopts.h" +#include "xiosigchld.h" #include "xiolockfile.h" +#include "xioopen.h" /* command line options */ 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 */ - 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 */ } socat_opts = { - 8192, /* bufsiz */ - false, /* verbose */ - false, /* verbhex */ - {1,0}, /* pollintv */ - {0,500000}, /* closwait */ - {0,0}, /* total_timeout */ - 0, /* debug */ 0, /* strictopts */ - 's', /* logopt */ - false, /* lefttoright */ - false, /* righttoleft */ { NULL, 0 }, /* lock */ }; void socat_usage(FILE *fd); void socat_version(FILE *fd); -int socat(const char *address1, const char *address2); -int _socat(void); -int cv_newline(unsigned char **buff, ssize_t *bytes, int lineterm1, int lineterm2); +int socat(int argc, const char *address1, const char *address2); +int _socat(xiofile_t *xfd1, xiofile_t *xfd2); void socat_signal(int sig); -static int socat_sigchild(struct single *file); void lftocrlf(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 priority and are to be overridden by options */ - if (xioinitialize() != 0) { + if (xioinitialize(XIO_MAYALL) != 0) { Exit(1); } - xiosetopt('p', "!!"); + xiosetopt('p', "%"); xiosetopt('o', ":"); argc0 = argc; /* save for later use */ @@ -114,14 +94,14 @@ int main(int argc, const char *argv[]) { #endif /* WITH_HELP */ case 'd': diag_set('d', NULL); break; #if WITH_FILAN - case 'D': socat_opts.debug = true; break; + case 'D': xioparams->debug = true; break; #endif case 'l': switch (arg1[0][2]) { case 'm': /* mixed mode: stderr, then switch to syslog; + facility */ diag_set('s', NULL); xiosetopt('l', "m"); - socat_opts.logopt = arg1[0][2]; + xioparams->logopt = arg1[0][2]; xiosetopt('y', &arg1[0][3]); break; case 'y': /* syslog + facility */ @@ -152,8 +132,8 @@ int main(int argc, const char *argv[]) { break; } break; - case 'v': socat_opts.verbose = true; break; - case 'x': socat_opts.verbhex = true; break; + case 'v': xioparams->verbose = true; break; + case 'x': xioparams->verbhex = true; break; case 'b': if (arg1[0][2]) { a = *arg1+2; } else { @@ -163,7 +143,7 @@ int main(int argc, const char *argv[]) { Exit(1); } } - socat_opts.bufsiz = strtoul(a, (char **)&a, 0); + xioparams->bufsiz = strtoul(a, (char **)&a, 0); break; case 's': diag_set_int('e', E_FATAL); break; @@ -177,9 +157,9 @@ int main(int argc, const char *argv[]) { } } rto = strtod(a, (char **)&a); - socat_opts.closwait.tv_sec = rto; - socat_opts.closwait.tv_usec = - (rto-socat_opts.closwait.tv_sec) * 1000000; + xioparams->closwait.tv_sec = rto; + xioparams->closwait.tv_usec = + (rto-xioparams->closwait.tv_sec) * 1000000; break; case 'T': if (arg1[0][2]) { a = *arg1+2; @@ -191,12 +171,12 @@ int main(int argc, const char *argv[]) { } } rto = strtod(a, (char **)&a); - socat_opts.total_timeout.tv_sec = rto; - socat_opts.total_timeout.tv_usec = - (rto-socat_opts.total_timeout.tv_sec) * 1000000; + xioparams->total_timeout.tv_sec = rto; + xioparams->total_timeout.tv_usec = + (rto-xioparams->total_timeout.tv_sec) * 1000000; break; - case 'u': socat_opts.lefttoright = true; break; - case 'U': socat_opts.righttoleft = true; break; + case 'u': xioparams->lefttoright = true; break; + case 'U': xioparams->righttoleft = true; break; case 'g': xioopts_ignoregroups = true; break; case 'L': if (socat_opts.lock.lockfile) Error("only one -L and -W option allowed"); @@ -237,8 +217,9 @@ int main(int argc, const char *argv[]) { break; #endif /* WITH_IP4 || WITH_IP6 */ case '\0': + case '-': /*! this is hardcoded "--" */ case ',': - case ':': break; /* this "-" is a variation of STDIO */ + case ':': break; /* this "-" is a variation of STDIO or -- */ default: xioinqopt('p', buff, sizeof(buff)); if (arg1[0][1] == buff[0]) { @@ -251,15 +232,20 @@ int main(int argc, const char *argv[]) { xioinqopt('p', buff, sizeof(buff)); if (arg1[0][0] == '-' && (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; ++arg1; --argc; } +#if 0 + Info1("%d address arguments", argc); +#else if (argc != 2) { Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc); Exit(1); } - if (socat_opts.lefttoright && socat_opts.righttoleft) { +#endif + if (xioparams->lefttoright && xioparams->righttoleft) { Error("-U and -u must not be combined"); } @@ -291,6 +277,26 @@ int main(int argc, const char *argv[]) { Signal(SIGFPE, socat_signal); Signal(SIGSEGV, 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 */ xiohook_newchild = &socat_newchild; @@ -304,7 +310,7 @@ int main(int argc, const char *argv[]) { Atexit(socat_unlock); - result = socat(arg1[0], arg1[1]); + result = socat(argc, arg1[0], arg1[1]); Notice1("exiting with status %d", result); Exit(result); 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 addresses are extracted (but not resolved). */ -int socat(const char *address1, const char *address2) { - int mayexec; +int socat(int argc, const char *address1, const char *address2) { + xiofile_t *xfd1, *xfd2; + xioinitialize(XIO_MAYALL); #if 1 if (Signal(SIGPIPE, SIG_IGN) == SIG_ERR) { Warn1("signal(SIGPIPE, SIG_IGN): %s", strerror(errno)); } #endif - if (socat_opts.lefttoright) { - if ((sock1 = xioopen(address1, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) { + /* open the first (left most) address */ + if (xioparams->lefttoright) { + if ((xfd1 = socat_open(address1, XIO_RDONLY, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) { return -1; } - xiosetsigchild(sock1, socat_sigchild); - } else if (socat_opts.righttoleft) { - if ((sock1 = xioopen(address1, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) { + } else if (xioparams->righttoleft) { + if ((xfd1 = socat_open(address1, XIO_WRONLY, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) { return -1; } - xiosetsigchild(sock1, socat_sigchild); } 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; } - xiosetsigchild(sock1, socat_sigchild); } + xiosetsigchild(xfd1, socat_sigchild); #if 1 /*! */ - if (XIO_READABLE(sock1) && - (XIO_RDSTREAM(sock1)->howtoend == END_KILL || - XIO_RDSTREAM(sock1)->howtoend == END_CLOSE_KILL || - XIO_RDSTREAM(sock1)->howtoend == END_SHUTDOWN_KILL)) { - 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; */ - } 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; - } + if (XIO_RDSTREAM(xfd1)->subaddrstat < 0) { + Info1("child "F_pid" has already died", + XIO_RDSTREAM(xfd1)->child.pid); + XIO_RDSTREAM(xfd1)->child.pid = 0; + /* return STAT_RETRYLATER; */ } #endif - mayexec = (sock1->common.flags&XIO_DOESCONVERT ? 0 : XIO_MAYEXEC); - if (XIO_WRITABLE(sock1)) { - if (XIO_READABLE(sock1)) { - if ((sock2 = xioopen(address2, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) { + /* second (right) addresses chain */ + if (XIO_WRITABLE(xfd1)) { + if (XIO_READABLE(xfd1)) { + if ((xfd2 = socat_open(address2, XIO_RDWR, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYEXEC|XIO_MAYCONVERT)) == NULL) { return -1; } - xiosetsigchild(sock2, socat_sigchild); } 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; } - xiosetsigchild(sock2, socat_sigchild); } } 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; } - xiosetsigchild(sock2, socat_sigchild); } + xiosetsigchild(xfd2, socat_sigchild); #if 1 /*! */ - if (XIO_READABLE(sock2) && - (XIO_RDSTREAM(sock2)->howtoend == END_KILL || - XIO_RDSTREAM(sock2)->howtoend == END_CLOSE_KILL || - XIO_RDSTREAM(sock2)->howtoend == END_SHUTDOWN_KILL)) { - 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; */ - } 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; - } + if (XIO_RDSTREAM(xfd2)->subaddrstat < 0) { + Info1("child "F_pid" has already died", + XIO_RDSTREAM(xfd2)->child.pid); + XIO_RDSTREAM(xfd2)->child.pid = 0; + /* return STAT_RETRYLATER; */ } #endif Info("resolved and opened all sock addresses"); 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 child already died, leaving some data for us. returns <0 if an error occurred; @@ -646,10 +602,10 @@ int childleftdata(xiofile_t *xfd) { int retval; /* have to check if a child process died before, but left read data */ if (XIO_READABLE(xfd) && - (XIO_RDSTREAM(xfd)->howtoend == END_KILL || - XIO_RDSTREAM(xfd)->howtoend == END_CLOSE_KILL || - XIO_RDSTREAM(xfd)->howtoend == END_SHUTDOWN_KILL) && - XIO_RDSTREAM(xfd)->para.exec.pid == 0) { + (/*0 XIO_RDSTREAM(xfd)->howtoclose == END_KILL ||*/ + XIO_RDSTREAM(xfd)->howtoclose == END_CLOSE_KILL || + XIO_RDSTREAM(xfd)->howtoclose == END_SHUTDOWN_KILL) && + XIO_RDSTREAM(xfd)->child.pid == 0) { struct timeval time0 = { 0,0 }; 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);*/ } do { - retval = Select(FOPEN_MAX, &in, &out, &expt, &time0); + 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", - 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)); #else 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)); #endif return -1; @@ -681,9 +637,9 @@ int childleftdata(xiofile_t *xfd) { } return 0; } +#endif /* 0 */ -int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe, - unsigned char **buff, size_t bufsiz, bool righttoleft); +#if 0 bool mayrd1; /* sock1 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), and their options are set/applied returns -1 on error or 0 on success */ -int _socat(void) { +int _socat(xiofile_t *xfd1, xiofile_t *xfd2) { fd_set in, out, expt; int retval; unsigned char *buff; @@ -702,6 +658,9 @@ int _socat(void) { int wasaction = 1; /* last select was active, do NOT sleep before next */ struct timeval total_timeout; /* the actual total timeout timer */ + sock1 = xfd1; + sock2 = xfd2; + #if WITH_FILAN if (socat_opts.debug) { int fdi, fdo; @@ -732,7 +691,7 @@ int _socat(void) { #endif /* WITH_FILAN */ /* 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 (socat_opts.logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') { @@ -818,6 +777,7 @@ int _socat(void) { if (XIO_READABLE(sock1) && !(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof) && !socat_opts.righttoleft) { + Debug3("*** sock1: %p [%d,%d]", sock1, XIO_GETRDFD(sock1), XIO_GETWRFD(sock1)); if (!mayrd1) { FD_SET(XIO_GETRDFD(sock1), &in); } @@ -828,6 +788,7 @@ int _socat(void) { if (XIO_READABLE(sock2) && !(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof) && !socat_opts.lefttoright) { + Debug3("*** sock2: %p [%d,%d]", sock2, XIO_GETRDFD(sock2), XIO_GETWRFD(sock2)); if (!mayrd2) { FD_SET(XIO_GETRDFD(sock2), &in); } @@ -835,7 +796,7 @@ int _socat(void) { FD_SET(XIO_GETWRFD(sock1), &out); } } - retval = Select(FOPEN_MAX, &in, &out, &expt, to); + retval = Select(FD_SETSIZE, &in, &out, &expt, to); _errno = errno; if (retval < 0 && errno == EINTR) { Info1("select(): %s", strerror(errno)); @@ -851,12 +812,12 @@ int _socat(void) { if (retval < 0) { #if HAVE_FDS_BITS 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, strerror(errno)); #else 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, strerror(errno)); #endif @@ -900,7 +861,7 @@ int _socat(void) { if (mayrd1 && maywr2) { mayrd1 = false; - if ((bytes1 = xiotransfer(sock1, sock2, &buff, socat_opts.bufsiz, false)) + if ((bytes1 = xiotransfer(sock1, sock2, &buff, xioparams->bufsiz, false)) < 0) { if (errno != EAGAIN) { closing = MAX(closing, 1); @@ -920,15 +881,22 @@ int _socat(void) { /* avoid idle when all readbytes already there */ 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 { bytes1 = -1; } if (mayrd2 && maywr1) { mayrd2 = false; - if ((bytes2 = xiotransfer(sock2, sock1, &buff, socat_opts.bufsiz, true)) + if ((bytes2 = xiotransfer(sock2, sock1, &buff, xioparams->bufsiz, true)) < 0) { if (errno != EAGAIN) { closing = MAX(closing, 1); @@ -948,8 +916,15 @@ int _socat(void) { /* avoid idle when all readbytes already there */ 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 { bytes2 = -1; } @@ -959,7 +934,7 @@ int _socat(void) { if (bytes1 == 0 || XIO_RDSTREAM(sock1)->eof >= 2) { if (XIO_RDSTREAM(sock1)->ignoreeof && !closing) { Debug1("socket 1 (fd %d) is at EOF, ignoring", - XIO_RDSTREAM(sock1)->fd); /*! */ + XIO_RDSTREAM(sock1)->fd1); /*! */ polling = 1; } else { 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 (XIO_RDSTREAM(sock2)->ignoreeof && !closing) { Debug1("socket 2 (fd %d) is at EOF, ignoring", - XIO_RDSTREAM(sock2)->fd); + XIO_RDSTREAM(sock2)->fd1); polling = 1; } else { Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2)); @@ -991,8 +966,9 @@ int _socat(void) { return 0; } +#endif /* 0 */ - +#if 0 #define MAXTIMESTAMPLEN 128 /* prints the timestamp to the buffer and terminates it with '\0'. This buffer should be at least MAXTIMESTAMPLEN bytes long. @@ -1035,7 +1011,9 @@ int gettimestamp(char *timestamp) { #endif /* !HAVE_GETTIMEOFDAY */ return 0; } +#endif +#if 0 static const char *prefixltor = "> "; static const char *prefixrtol = "< "; static unsigned long numltor; @@ -1061,8 +1039,9 @@ static int fputs(buff, file); return 0; } +#endif /* 0 */ - +#if 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 @@ -1078,7 +1057,7 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe, unsigned char **buff, size_t bufsiz, bool righttoleft) { ssize_t bytes, writt; - bytes = xioread(inpipe, *buff, socat_opts.bufsiz); + bytes = xioread(inpipe, *buff, xioparams->bufsiz); if (bytes < 0) { if (errno != EAGAIN) XIO_RDSTREAM(inpipe)->eof = 2; @@ -1105,7 +1084,7 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe, errno = EAGAIN; return -1; } - if (socat_opts.verbose && socat_opts.verbhex) { + if (xioparams->verbose && xioparams->verbhex) { /* Hack-o-rama */ size_t i = 0; size_t j; @@ -1178,7 +1157,7 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe, } ++i; } - } else if (socat_opts.verbhex) { + } else if (xioparams->verbhex) { int i; /*! prefix? */ for (i = 0; i < bytes; ++i) { @@ -1206,11 +1185,13 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe, } return writt; } +#endif /* 0 */ + +#if 0 #define CR '\r' #define LF '\n' - int cv_newline(unsigned char **buff, ssize_t *bytes, int lineterm1, int lineterm2) { /* must perform newline changes */ @@ -1260,7 +1241,7 @@ int cv_newline(unsigned char **buff, ssize_t *bytes, } else { from = '\r'; } - if ((buf2 = Malloc(2*socat_opts.bufsiz+1)) == NULL) { + if ((buf2 = Malloc(2*xioparams->bufsiz+1)) == NULL) { return -1; } s = *buff; t = buf2; z = *buff + *bytes; @@ -1279,6 +1260,7 @@ int cv_newline(unsigned char **buff, ssize_t *bytes, } return 0; } +#endif /* 0 */ void socat_signal(int signum) { switch (signum) { @@ -1302,6 +1284,7 @@ void socat_signal(int signum) { Exit(128+signum); } +#if 0 /* this is the callback when the child of an address died */ static int socat_sigchild(struct single *file) { if (file->ignoreeof && !closing) { @@ -1312,6 +1295,7 @@ static int socat_sigchild(struct single *file) { } return 0; } +#endif static int socat_lock(void) { int lockrc; diff --git a/sslcls.c b/sslcls.c index 5bea174..c0fdd0b 100644 --- a/sslcls.c +++ b/sslcls.c @@ -197,6 +197,22 @@ int sycSSL_set_fd(SSL *ssl, int fd) { 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 result; Debug1("SSL_connect(%p)", ssl); diff --git a/sslcls.h b/sslcls.h index e3de001..bb61d86 100644 --- a/sslcls.h +++ b/sslcls.h @@ -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); long sycSSL_get_verify_result(SSL *ssl); 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_accept(SSL *ssl); 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_get_verify_result(s) SSL_get_verify_result(s) #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_accept(s) SSL_accept(s) #define sycSSL_read(s,b,n) SSL_read(s,b,n) diff --git a/sycls.c b/sycls.c index d30d9b3..64d185a 100644 --- a/sycls.c +++ b/sycls.c @@ -720,6 +720,41 @@ int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, 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 pid; int _errno; @@ -764,12 +799,15 @@ int Sigaction(int signum, const struct sigaction *act, } #endif /* HAVE_SIGACTION */ -int Sigprocmask(int how, const sigset_t *set, sigset_t *oset) { - int retval; - Debug3("sigprocmask(%d, %p, %p)", how, set, oset); - retval = sigprocmask(how, set, oset); - Debug1("sigprocmask() -> %d", retval); - return retval; +int Sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { + int _errno, result; + Debug3("sigprocmask(%d, {0x%lx}, %p)", how, *(unsigned long *)set, oldset); + result = sigprocmask(how, set, oldset); + _errno = errno; + 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) { @@ -1138,7 +1176,7 @@ int Pause(void) { return retval; } -#if WITH_IP4 || WITH_IP6 +#if _WITH_IP4 || _WITH_IP6 struct hostent *Gethostbyname(const char *name) { struct hostent *hent; Debug1("gethostbyname(\"%s\")", name); @@ -1154,7 +1192,7 @@ struct hostent *Gethostbyname(const char *name) { } return hent; } -#endif /* WITH_IP4 || WITH_IP6 */ +#endif /* _WITH_IP4 || _WITH_IP6 */ #if (_WITH_IP4 || _WITH_IP6) && HAVE_GETADDRINFO int Getaddrinfo(const char *node, const char *service, @@ -1397,6 +1435,27 @@ void Abort(void) { 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 result, _errno; Debug1("mkstemp(\"%s\")", template); @@ -1500,4 +1559,40 @@ void Add_history(const char *string) { #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 */ diff --git a/sycls.h b/sycls.h index ffe49db..565c483 100644 --- a/sycls.h +++ b/sycls.h @@ -75,6 +75,8 @@ int Chmod(const char *path, mode_t mode); int Poll(struct pollfd *ufds, unsigned int nfds, int timeout); int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, 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 Waitpid(pid_t pid, int *status, int options); #ifndef HAVE_TYPE_SIGHANDLER @@ -133,9 +135,13 @@ int Grantpt(int fd); int Unlockpt(int fd); int Gethostname(char *name, size_t len); int Uname(struct utsname *buf); +int Sigprocmask(int how, const sigset_t *set, sigset_t *oldset); int Atexit(void (*func)(void)); void Exit(int status); 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); char *Readline(const char *prompt); @@ -145,6 +151,12 @@ int Write_history(const char *filename); int Append_history(int nelements, const char *filename); int Read_history(const char *filename); 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 */ @@ -205,6 +217,7 @@ void Add_history(const char *string); #define Chmod(p,m) chmod(p,m) #define Poll(u, n, t) poll(u, n, 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 Waitpid(p,s,o) waitpid(p,s,o) #define Signal(s,h) signal(s,h) @@ -252,9 +265,12 @@ void Add_history(const char *string); #define Getpgid(p) getpgid(p) #define Gethostname(n,l) gethostname(n,l) #define Uname(b) uname(b) +#define Sigprocmask(h,s,o) sigprocmask(h,s,o) #define Atexit(f) atexit(f) #define Exit(s) exit(s) #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 Readline(p) readline(p) @@ -265,6 +281,11 @@ void Add_history(const char *string); #define Read_history(f) read_history(f) #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 /* !defined(__sycls_h_included) */ diff --git a/sysincludes.h b/sysincludes.h index a2b9f8a..6294cd6 100644 --- a/sysincludes.h +++ b/sysincludes.h @@ -67,10 +67,11 @@ #if HAVE_FCNTL_H #include /* open(), O_RDWR */ #endif +#include #if HAVE_NETDB_H && (_WITH_IP4 || _WITH_IP6) #include /* struct hostent, gethostbyname() */ #endif -#if HAVE_SYS_UN_H && WITH_UNIX +#if HAVE_SYS_UN_H && _WITH_UNIX #include /* struct sockaddr_un, unix domain sockets */ #endif #if HAVE_SYS_IOCTL_H diff --git a/sysutils.c b/sysutils.c index c10e2ea..344c75e 100644 --- a/sysutils.c +++ b/sysutils.c @@ -402,7 +402,7 @@ const char *hstrerror(int err) { #endif /* !HAVE_HSTRERROR */ -#if WITH_TCP || WITH_UDP +#if _WITH_TCP || _WITH_UDP /* returns port in network byte order */ int parseport(const char *portname, int ipproto) { struct servent *se; @@ -425,7 +425,7 @@ int parseport(const char *portname, int ipproto) { return se->s_port; } -#endif /* WITH_TCP || WITH_UDP */ +#endif /* _WITH_TCP || _WITH_UDP */ #if WITH_IP4 || WITH_IP6 /* check the systems interfaces for ifname and return its index diff --git a/sysutils.h b/sysutils.h index 7e326b8..28e33d4 100644 --- a/sysutils.h +++ b/sysutils.h @@ -17,15 +17,15 @@ union xioin6_u { union sockaddr_union { struct sockaddr soa; -#if WITH_UNIX +#if _WITH_UNIX struct sockaddr_un un; -#endif /* WITH_UNIX */ -#if WITH_IP4 +#endif /* _WITH_UNIX */ +#if _WITH_IP4 struct sockaddr_in ip4; -#endif /* WITH_IP4 */ -#if WITH_IP6 +#endif /* _WITH_IP4 */ +#if _WITH_IP6 struct sockaddr_in6 ip6; -#endif /* WITH_IP6 */ +#endif /* _WITH_IP6 */ } ; #if _WITH_IP4 diff --git a/test.sh b/test.sh index c1e6e5c..80d0aa1 100755 --- a/test.sh +++ b/test.sh @@ -25,7 +25,7 @@ export SOCAT_OPTS="$opts" #debug="1" debug= TESTS="$@" -INTERFACE=eth0; # not used for function tests +INTERFACE=eth1; # not used for function tests MCINTERFACE=lo # !!! Linux only #LOCALHOST=192.168.58.1 #LOCALHOST=localhost @@ -45,6 +45,16 @@ if ! type usleep >/dev/null 2>&1; then sleep $(((n+999999)/1000000)) } fi + +# a "real value" sleep +rsleep () { + local n="$1" + local s="${n%.*}" + local u="${n#*.}" + sleep "$s" + usleep "$((u*10**(6-${#u})))" +} + #USLEEP=usleep F_n="%3d" # format string for test numbers LANG=C @@ -89,7 +99,7 @@ esac # for some tests we need a second local IPv4 address case "$UNAME" in Linux) - BROADCASTIF=eth0 + BROADCASTIF=eth1 SECONDADDR=127.0.0.2 BCADDR=127.255.255.255 BCIFADDR=$($IFCONFIG $BROADCASTIF |grep 'inet ' |awk '{print($2);}' |cut -d: -f2) ;; @@ -124,7 +134,7 @@ case "$UNAME" in esac if [ -z "$SECONDIP6ADDR" ]; then case "$TESTS" in - *%root2%*) $IFCONFIG eth0 ::2/128 + *%root2%*) $IFCONFIG eth1 ::2/128 esac fi @@ -468,7 +478,7 @@ N=1 #for o in $(filloptionvalues $OPTS|tr ',' ' '); do # echo testing if $METHOD accepts option $o # touch $TF -# $SOCAT $opts -!!$method:$TF,$o /dev/null,ignoreof /dev/null rm -f $TF done @@ -1203,7 +1213,7 @@ for addr in gopen; do for o in $(filloptionvalues $OPTS|tr ',' ' '); do echo testing if $ADDR on existing device accepts option $o rm -f $TF; mknod $TF c 1 3 - $SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof "$tf" 2>"$te" #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=$! #sleep 5 && kill $rc1 2>/dev/null & # rc2=$! @@ -1461,6 +1471,44 @@ testecho () { 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 # flush of od buffers testod () { @@ -1469,14 +1517,14 @@ testod () { local arg1="$3"; [ -z "$arg1" ] && arg1="-" local arg2="$4"; [ -z "$arg2" ] && arg2="echo" 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 te="$td/test$N.stderr" local tdiff="$td/test$N.diff" local dain="$(date)" local daout="$(echo "$dain" |od -c)" $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 $PRINTF "$FAILED: $SOCAT:\n" echo "$SOCAT $opts $arg1 $arg2" @@ -1771,7 +1819,7 @@ waitudp6port () { Linux) l=$(netstat -an |grep '^udp[6 ] .* .*[0-9*:]:'$port' [ ]*:::\*') ;; FreeBSD) l=$(netstat -an |egrep '^udp(6|46) .*[0-9*]\.'$port' .* \*\.\*') ;; NetBSD) l=$(netstat -an |grep '^udp6 .* \*\.'$port' [ ]* \*\.\*') ;; - OpenBSD) l=$(netstat -an |grep '^udp6 .*[0-9*]\.'$port' [ ]* \*\.\*') ;; + OpenBSD) l=$(netstat -an |grep '^udp6 .*[0-9*]\.'$port' [ ]* \*\.\*') ;; #Darwin) l=$(netstat -an |grep '^udp6.* .*[0-9*]\.'$port' .* \*\.\* ') ;; AIX) l=$(netstat -an |grep '^udp[6 ] 0 0 .*[*0-9]\.'$port' .* \*\.\*[ ]*$') ;; SunOS) l=$(netstat -an -f inet6 -P udp |grep '.*[1-9*]\.'$port' [ ]*Idle') ;; @@ -1816,17 +1864,20 @@ gentestcert () { local name="$1" 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 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 } # generate a test DSA key and certificate gentestdsacert () { +#set -vx 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 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 } @@ -1861,8 +1912,8 @@ N=$((N+1)) NAME=DUALSTDIO case "$TESTS" in *%functions%*|*%stdio%*|*%$NAME%*) -TEST="$NAME: splitted form of stdio ('stdin!!stdout') with simple echo via internal pipe" -testecho "$N" "$TEST" "stdin!!stdout" "pipe" "$opts" +TEST="$NAME: splitted form of stdio ('stdout%stdin') with simple echo via internal pipe" +testecho "$N" "$TEST" "stdout%stdin" "pipe" "$opts" esac N=$((N+1)) @@ -1870,8 +1921,8 @@ N=$((N+1)) NAME=DUALSHORTSTDIO case "$TESTS" in *%functions%*|*%stdio%*|*%$NAME%*) -TEST="$NAME: short splitted form of stdio ('-!!-') with simple echo via internal pipe" -testecho "$N" "$TEST" "-!!-" "pipe" "$opts" +TEST="$NAME: short splitted form of stdio ('-%-') with simple echo via internal pipe" +testecho "$N" "$TEST" "-%-" "pipe" "$opts" esac N=$((N+1)) @@ -1880,7 +1931,7 @@ NAME=DUALFDS case "$TESTS" in *%functions%*|*%fd%*|*%$NAME%*) 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 N=$((N+1)) @@ -1897,14 +1948,15 @@ esac N=$((N+1)) -NAME=DUALPIPE -case "$TESTS" in -*%functions%*|*%pipe%*|*%$NAME%*) -TEST="$NAME: simple echo via named pipe, specified twice" -tp="$td/pipe$N" -testecho "$N" "$TEST" "" "pipe:$tp,nonblock!!pipe:$tp" "$opts" -esac -N=$((N+1)) +# does not work with % +#NAME=DUALPIPE +#case "$TESTS" in +#*%functions%*|*%pipe%*|*%$NAME%*) +#TEST="$NAME: simple echo via named pipe, specified twice" +#tp="$td/pipe$N" +#testecho "$N" "$TEST" "" "pipe:$tp%pipe:$tp,nonblock" "$opts" +#esac +#N=$((N+1)) NAME=FILE @@ -1912,7 +1964,7 @@ case "$TESTS" in *%functions%*|*%file%*|*%ignoreeof%*|*%$NAME%*) TEST="$NAME: simple echo via file" tf="$td/file$N" -testecho "$N" "$TEST" "" "$tf,ignoreeof!!$tf" "$opts" +testecho "$N" "$TEST" "" "$tf%$tf,ignoreeof" "$opts" esac N=$((N+1)) @@ -1994,7 +2046,8 @@ NAME=DUALSYSTEMFDS case "$TESTS" in *%functions%*|*%system%*|*%$NAME%*) 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 N=$((N+1)) @@ -2003,7 +2056,7 @@ NAME=EXECSOCKETFLUSH case "$TESTS" in *%functions%*|*%exec%*|*%$NAME%*) 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 N=$((N+1)) @@ -2012,7 +2065,7 @@ NAME=SYSTEMSOCKETFLUSH case "$TESTS" in *%functions%*|*%system%*|*%$NAME%*) 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 N=$((N+1)) @@ -2081,7 +2134,7 @@ N=$((N+1)) #case "$TESTS" in #*%functions%*|*%system%*|*%$NAME%*) #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 #N=$((N+1)) @@ -2227,7 +2280,7 @@ TEST="$NAME: echo via two unidirectional UDP IPv4 sockets" tf="$td/file$N" p1=$PORT 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 PORT=$((PORT+2)) N=$((N+1)) @@ -2248,7 +2301,7 @@ ts="$td/test$N.socket" tdiff="$td/test$N.diff" da=$(date) CMD1="$SOCAT $opts UNIX-LISTEN:$ts PIPE" -CMD2="$SOCAT $opts -!!- UNIX:$ts" +CMD2="$SOCAT $opts -%- UNIX:$ts" printf "test $F_n $TEST... " $N $CMD1 $tf 2>"${te}1" & bg=$! # background process id @@ -2285,7 +2338,7 @@ tsl=$PORT ts="127.0.0.1:$tsl" da=$(date) 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 $CMD1 >"$tf" 2>"${te}1" & waittcp4port $tsl 1 @@ -2325,7 +2378,7 @@ tsl=$PORT ts="[::1]:$tsl" da=$(date) 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 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id @@ -2371,7 +2424,7 @@ tsl=$PORT ts="127.0.0.1:$tsl" da=$(date) 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 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id @@ -2417,7 +2470,7 @@ tsl=$PORT ts="[::1]:$tsl" da=$(date) 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 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id @@ -2465,7 +2518,7 @@ tsl=$PORT ts="127.0.0.1:$tsl" da=$(date) 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 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id @@ -2513,7 +2566,7 @@ tsl=$PORT ts="127.0.0.1:$tsl" da=$(date) 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 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id @@ -2558,7 +2611,7 @@ tsl=$PORT ts="127.0.0.1:$tsl" da=$(date) 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 SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id @@ -2603,7 +2656,7 @@ tsl=$PORT ts="[::1]:$tsl" da=$(date) 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 SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id @@ -2651,7 +2704,7 @@ tsl=$PORT ts="127.0.0.1:$tsl" da=$(date) 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 SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id @@ -2696,7 +2749,7 @@ tsl=$PORT ts="[::1]:$tsl" da=$(date) 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 SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id @@ -2745,7 +2798,7 @@ tsl=$PORT ts="127.0.0.1:$tsl" da=$(date) 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 SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id @@ -2790,7 +2843,7 @@ tsl=$PORT ts="[::1]:$tsl" da=$(date) 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 SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id @@ -2915,7 +2968,7 @@ te="$td/test$N.stderr" tdiff="$td/test$N.diff" da=$(date) 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 $CMD >"$tf2" 2>"$te" if [ $? -ne 0 ]; then @@ -2945,7 +2998,7 @@ tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" 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 #mknod $tp p # no mknod p on FreeBSD mkfifo $tp @@ -3121,9 +3174,9 @@ case "$TESTS" in TEST="$NAME: exec against address with ignoreeof" tf="$td/test$N.stdout" 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 -$CMD >"$tf" 2>"$te" +$CMD >"$tf" if [ -s "$te" ]; then $PRINTF "$FAILED: $SOCAT:\n" echo "$CMD" @@ -3337,6 +3390,119 @@ esac 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 case "$TESTS" in *%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) @@ -3358,12 +3524,15 @@ tdiff="$td/test$N.diff" da=$(date) 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,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 eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id 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 $PRINTF "$FAILED: $SOCAT:\n" echo "$CMD2 &" @@ -3401,8 +3570,10 @@ tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da=$(date) -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 OPENSSL-LISTEN:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe" +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 eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id @@ -3625,7 +3796,8 @@ tdiff="$td/test$N.diff" da="$(date)" da="$da$($ECHO '\r')" # we have a normal tcp echo listening - so the socks header must appear in answer 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 eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id @@ -3712,7 +3884,8 @@ tdiff="$td/test$N.diff" da="$(date)" da="$da$($ECHO '\r')" # 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\"" -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 eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id @@ -3800,7 +3973,8 @@ tdiff="$td/test$N.diff" 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,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 eval "$CMD2 2>\"${te}2\" &" pid=$! # background process id @@ -3882,7 +4056,7 @@ tsl=$PORT ts="127.0.0.1:$tsl" da=$(date) 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 #$CMD1 >"$tf" 2>"${te}1" & $CMD1 >/dev/null 2>"${te}1" & @@ -3944,7 +4118,7 @@ N=$((N+1)) #da=$(date) #$SOCAT UDP-listen:$tsl PIPE & #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 # $ECHO "... test $N succeeded" # numOK=$((numOK+1)) @@ -4068,7 +4242,8 @@ tdiff="$td/test$N.diff" 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 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 eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id @@ -4129,7 +4304,7 @@ NAME=SINGLEEXECOUTSOCKETPAIR case "$TESTS" in *%functions%*|*%$NAME%*) 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 N=$((N+1)) @@ -4137,7 +4312,7 @@ NAME=SINGLEEXECOUTPIPE case "$TESTS" in *%functions%*|*%$NAME%*) 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 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 numCANT=$((numCANT+1)) else -testecho "$N" "$TEST" "-!!exec:cat,pty,raw" "" "$opts" 1 +testecho "$N" "$TEST" "exec:cat,pty,raw%-" "" "$opts" 1 fi esac N=$((N+1)) @@ -4158,7 +4333,7 @@ NAME=SINGLEEXECINSOCKETPAIR case "$TESTS" in *%functions%*|*%$NAME%*) TEST="$NAME: inheritance of stdin to single exec with socketpair" -testecho "$N" "$TEST" "exec:cat!!-" "" "$opts" +testecho "$N" "$TEST" "-%exec:cat" "" "$opts" esac N=$((N+1)) @@ -4166,7 +4341,7 @@ NAME=SINGLEEXECINPIPE case "$TESTS" in *%functions%*|*%$NAME%*) 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 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 numCANT=$((numCANT+1)) else -testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts" $MISCDELAY +testecho "$N" "$TEST" "-%exec:cat,pty,raw" "" "$opts" $MISCDELAY fi esac 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 numCANT=$((numCANT+1)) else -testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts" +testecho "$N" "$TEST" "-%exec:cat,pty,raw" "" "$opts" fi esac N=$((N+1)) @@ -4217,7 +4392,7 @@ tr="$td/test$N.ref" tdiff="$td/test$N.diff" da="$(date)" da="$da$($ECHO '\r')" # 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" #chmod a+x "$ts" 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 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 -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 #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 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 @@ -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 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 -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 -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 -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 CMD6="$SOCAT $opts -lpclient -t5 - tcp4:$LOCALHOST:$((PORT+4)),retry=3" printf "test $F_n $TEST... " $N @@ -4594,7 +4776,9 @@ testserversec () { #set -vx # assemble address w/ security option; on dual, take read part: case "$arg1" in - *!!*) arg="${arg1%!!*},$secopt1!!${arg1#*!!}" ;; + #*!!*) arg="${arg1%!!*},$secopt1!!${arg1#*!!}" ;; + #*%*) arg="${arg1%\%*}%${arg1#*%},$secopt1" ;; + *%*) arg="$arg1,$secopt1" ;; *) arg="$arg1,$secopt1" ;; esac # start server @@ -5323,8 +5507,10 @@ tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da=$(date) -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 OPENSSL-LISTEN:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cert=$SRVCERT.pem,key=$SRVCERT.key,verify=0 pipe" +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 eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id @@ -5690,7 +5876,7 @@ tsl=$PORT ts="127.0.0.1:$tsl" da=$(date) 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 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id @@ -6250,7 +6436,7 @@ PORT2=$PORT; PORT=$((PORT+1)) PORT3=$PORT # 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 -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 esac PORT=$((PORT+1)) @@ -6268,7 +6454,7 @@ PORT1=$PORT; PORT=$((PORT+1)) PORT2=$PORT # 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 -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 esac PORT=$((PORT+1)) @@ -6286,7 +6472,7 @@ PORT1=$PORT; PORT=$((PORT+1)) PORT2=$PORT # 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 -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 esac PORT=$((PORT+1)) @@ -6308,7 +6494,7 @@ $ECHO "socat: $SECONDADDR" >"$ha" $ECHO "ALL: ALL" >"$hd" # 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 -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 esac PORT=$((PORT+1)) @@ -6390,7 +6576,7 @@ PORT2=$PORT; PORT=$((PORT+1)) PORT3=$PORT # 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 -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 esac PORT=$((PORT+1)) @@ -6408,7 +6594,7 @@ PORT1=$PORT; PORT=$((PORT+1)) PORT2=$PORT # 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 -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 esac PORT=$((PORT+1)) @@ -6426,7 +6612,7 @@ PORT1=$PORT; PORT=$((PORT+1)) PORT2=$PORT # 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 -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 esac PORT=$((PORT+1)) @@ -6448,7 +6634,7 @@ PORT1=$PORT; PORT=$((PORT+1)) PORT2=$PORT # 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 -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 esac PORT=$((PORT+1)) @@ -6467,7 +6653,7 @@ elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then numCANT=$((numCANT+1)) 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!!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 esac PROTO=$((PROTO+1)) @@ -6490,7 +6676,7 @@ hd="$td/hosts.deny" $ECHO "socat: $SECONDADDR" >"$ha" $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!!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 esac PROTO=$((PROTO+1)) @@ -6513,7 +6699,7 @@ PROTO1=$PROTO; PROTO=$((PROTO+1)) PROTO2=$PROTO # 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 -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 esac PROTO=$((PROTO+1)) @@ -6540,7 +6726,7 @@ $ECHO "socat: $SECONDADDR" >"$ha" $ECHO "ALL: ALL" >"$hd" # 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 -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 esac PROTO=$((PROTO+1)) @@ -6559,7 +6745,7 @@ elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then numCANT=$((numCANT+1)) 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!!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 esac PROTO=$((PROTO+1)) @@ -6582,7 +6768,7 @@ hd="$td/hosts.deny" $ECHO "socat: [::2]" >"$ha" $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!!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 esac PROTO=$((PROTO+1)) @@ -6605,7 +6791,7 @@ PROTO1=$PROTO; PROTO=$((PROTO+1)) PROTO2=$PROTO # 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 -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 esac PROTO=$((PROTO+1)) @@ -6630,7 +6816,7 @@ $ECHO "socat: [::2]" >"$ha" $ECHO "ALL: ALL" >"$hd" # 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 -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 esac PROTO=$((PROTO+1)) @@ -6836,10 +7022,27 @@ esac 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 case "$TESTS" in *%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" te="$td/test$N.stderr" tdiff="$td/test$N.diff" @@ -6848,7 +7051,7 @@ p2=$PORT da1a="$(date) $RANDOM" da1b="$(date) $RANDOM" 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 -" printf "test $F_n $TEST... " $N $CMD3 >"$tf" 2>"${te}3" & @@ -6882,11 +7085,21 @@ esac PORT=$((PORT+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 case "$TESTS" in *%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" te="$td/test$N.stderr" ts="$td/test$N.sock" @@ -6894,7 +7107,7 @@ tdiff="$td/test$N.diff" da1a="$(date) $RANDOM" da1b="$(date) $RANDOM" 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 $CMD 2>"${te}2" & pid2=$! @@ -6906,16 +7119,18 @@ usleep 100000 kill "$pid2" 2>/dev/null wait if [ $? -ne 0 ]; then - $PRINTF "$FAILED: $SOCAT:\n" + $PRINTF "$FAILED\n" echo "$CMD1 &" - echo "$CMD2" + echo "$CMD" cat "${te}1a" "${te}1b" "${te}2" - $PRINTF "$FAILED: $SOCAT:\n" + numFAIL=$((numFAIL+1)) elif ! echo -e "$da1a\n$da1b" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" + echo "$CMD1 &" + echo "$CMD" cat "$tdiff" cat "${te}1a" "${te}1b" "${te}2" - $PRINTF "$FAILED: $SOCAT:\n" + numFAIL=$((numFAIL+1)) else $PRINTF "$OK\n" 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" tdiff="$td/test$N.diff" 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 (sleep 1; echo) |eval "$CMD" >"$to" 2>"$te" if test -s "$to"; then diff --git a/xio-creat.c b/xio-creat.c index edc490a..2f26cc9 100644 --- a/xio-creat.c +++ b/xio-creat.c @@ -1,5 +1,5 @@ -/* $Id: xio-creat.c,v 1.16 2006/07/13 06:39:01 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001-2006 */ +/* $Id: xio-creat.c,v 1.16.2.1 2006/07/24 19:17:32 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ /* 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 */ -const struct addrdesc addr_creat = { "create", 3, xioopen_creat, GROUP_FD|GROUP_NAMED|GROUP_FILE, 0, 0, 0 HELP(":") }; - +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(":") }; +const union xioaddr_desc *xioaddrs_creat[] = { + (union xioaddr_desc *)&xioaddr_creat1, + NULL +}; /* retrieve the mode option and perform the creat() call. 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]); if ((result = _xioopen_creat(filename, rw, opts)) < 0) return result; - fd->stream.fd = result; + fd->stream.fd1 = fd->stream.fd2 = result; + fd->stream.fdtype = FDTYPE_SINGLE; 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; - 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) return result; diff --git a/xio-creat.h b/xio-creat.h index afe8073..94b4c34 100644 --- a/xio-creat.h +++ b/xio-creat.h @@ -1,10 +1,10 @@ -/* $Id: xio-creat.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001 */ +/* $Id: xio-creat.h,v 1.4.2.1 2006/07/24 19:17:34 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_creat_h_included #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) */ diff --git a/xio-exec.c b/xio-exec.c index 2b2c3cd..6f0300f 100644 --- a/xio-exec.c +++ b/xio-exec.c @@ -1,8 +1,11 @@ -/* $Id: xio-exec.c,v 1.19 2006/07/12 21:59:28 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001-2006 */ +/* $Id: xio-exec.c,v 1.19.2.1 2006/07/24 19:17:35 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* 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 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 "xioopen.h" @@ -13,18 +16,25 @@ #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. */ xiofile_t *fd, unsigned groups, 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(":") }; + +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(":") }; + +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 }; -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. */ xiofile_t *fd, unsigned groups, @@ -39,7 +49,7 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts, 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) { /* child */ const char *ends[] = { " ", NULL }; @@ -74,7 +84,7 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts, token = Malloc(len); /*! */ tokp = token; if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests, - true, true, false) < 0) { + false, true, true, false) < 0) { Error("internal: miscalculated string lengths"); } *tokp++ = '\0'; @@ -89,7 +99,7 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts, ++strp; pargv[pargc++] = tokp; if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests, - true, true, false) < 0) { + false, true, true, false) < 0) { Error("internal: miscalculated string lengths"); } *tokp++ = '\0'; @@ -134,4 +144,5 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts, /* parent */ return 0; } + #endif /* WITH_EXEC */ diff --git a/xio-exec.h b/xio-exec.h index ab84aed..3a70212 100644 --- a/xio-exec.h +++ b/xio-exec.h @@ -1,11 +1,11 @@ -/* $Id: xio-exec.h,v 1.6 2002/05/19 08:05:36 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001, 2002 */ +/* $Id: xio-exec.h,v 1.6.2.1 2006/07/24 19:17:37 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_exec_h_included #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; diff --git a/xio-fd.c b/xio-fd.c index e9c29b9..5915583 100644 --- a/xio-fd.c +++ b/xio-fd.c @@ -1,5 +1,5 @@ /* $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 */ /* 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 }; /* 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 }; diff --git a/xio-fd.h b/xio-fd.h index 6e3ed7d..38b22d0 100644 --- a/xio-fd.h +++ b/xio-fd.h @@ -1,5 +1,5 @@ /* $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 */ #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_cool_write; extern const struct optdesc opt_end_close; +extern const struct optdesc opt_shut_none; #endif /* !defined(__xio_fd_h_included) */ diff --git a/xio-fdnum.c b/xio-fdnum.c index 859a816..25bf91f 100644 --- a/xio-fdnum.c +++ b/xio-fdnum.c @@ -1,5 +1,5 @@ -/* $Id: xio-fdnum.c,v 1.13 2006/07/08 10:03:14 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001-2006 */ +/* $Id: xio-fdnum.c,v 1.13.2.1 2006/07/24 19:17:38 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ /* 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); -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(":") }; +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(":") }; +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("::") }; +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. */ 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) { char *a1; int rw = (xioflags&XIO_ACCMODE); - int numfd; + int numfd1, numfd2 = -1; int result; - if (argc != 2) { - Error3("%s:%s: wrong number of parameters (%d instead of 1)", argv[0], argv[1], argc-1); + if (argc < 2 || argc > 3) { + 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') { Error1("error in FD number \"%s\"", argv[1]); } /* we dont want to see these fds in child processes */ - if (Fcntl_l(numfd, F_SETFD, FD_CLOEXEC) < 0) { - Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", numfd, strerror(errno)); + if (Fcntl_l(numfd1, F_SETFD, FD_CLOEXEC) < 0) { + 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 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. 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->howtoend = END_NONE; + xfd->stream.fd1 = numfd1; + xfd->stream.fd2 = numfd2; + if (numfd2 >= 0) { + xfd->stream.fdtype = FDTYPE_DOUBLE; + } else { + xfd->stream.fdtype = FDTYPE_SINGLE; + } #if WITH_TERMIOS - if (Isatty(xfd->fd)) { - if (Tcgetattr(xfd->fd, &xfd->savetty) < 0) { + if (Isatty(xfd->stream.fd1)) { + if (Tcgetattr(xfd->stream.fd1, &xfd->stream.savetty) < 0) { Warn2("cannot query current terminal settings on fd %d: %s", - xfd->fd, strerror(errno)); + xfd->stream.fd1, strerror(errno)); } else { - xfd->ttyvalid = true; + xfd->stream.ttyvalid = true; } } #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); - 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 */ diff --git a/xio-fdnum.h b/xio-fdnum.h index f9acf03..88c4e95 100644 --- a/xio-fdnum.h +++ b/xio-fdnum.h @@ -1,12 +1,13 @@ -/* $Id: xio-fdnum.h,v 1.6 2006/03/21 20:48:31 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001-2006 */ +/* $Id: xio-fdnum.h,v 1.6.2.1 2006/07/24 19:17:40 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_fdnum_h_included #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) */ diff --git a/xio-file.c b/xio-file.c index 2156913..303a1fa 100644 --- a/xio-file.c +++ b/xio-file.c @@ -11,7 +11,7 @@ #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 @@ -66,13 +66,17 @@ const struct optdesc opt_o_trunc = { "o-trunc", "trunc", OPT_O_TRUNC, #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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_open[] = { + (union xioaddr_desc *)&xioaddr_open1, + NULL +}; /* open for writing: if the filesystem entry already exists, 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]; int rw = (xioflags & XIO_ACCMODE); 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]); if ((result = _xioopen_open(filename, rw, opts)) < 0) return result; - fd->stream.fd = result; + fd->stream.fd1 = result; + fd->stream.fdtype = FDTYPE_SINGLE; #if WITH_TERMIOS - if (Isatty(fd->stream.fd)) { - if (Tcgetattr(fd->stream.fd, &fd->stream.savetty) < 0) { + if (Isatty(fd->stream.fd1)) { + if (Tcgetattr(fd->stream.fd1, &fd->stream.savetty) < 0) { Warn2("cannot query current terminal settings on fd %d: %s", - fd->stream.fd, strerror(errno)); + fd->stream.fd1, strerror(errno)); } else { 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 */ applyopts_named(filename, opts, PH_FD); - applyopts(fd->stream.fd, opts, PH_FD); - applyopts_cloexec(fd->stream.fd, opts); + applyopts(fd->stream.fd1, opts, PH_FD); + 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) return result; diff --git a/xio-file.h b/xio-file.h index 03d16c9..eba1ae4 100644 --- a/xio-file.h +++ b/xio-file.h @@ -1,5 +1,5 @@ -/* $Id: xio-file.h,v 1.8 2006/07/13 21:19:15 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001-2006 */ +/* $Id: xio-file.h,v 1.8.2.1 2006/07/24 19:17:44 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #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_noatime; -extern const struct addrdesc addr_open; +extern const union xioaddr_desc *xioaddrs_open[]; #endif /* !defined(__xio_file_h_included) */ diff --git a/xio-gopen.c b/xio-gopen.c index 3108da8..8d3fa66 100644 --- a/xio-gopen.c +++ b/xio-gopen.c @@ -14,12 +14,17 @@ #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(":") }; +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(":") }; -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]; flags_t openflags = (xioflags & XIO_ACCMODE); 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() */ 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)); return STAT_RETRYLATER; } - /*0 Info2("socket(PF_UNIX, %d, 0) -> %d", socktype, fd->stream.fd);*/ - applyopts(fd->stream.fd, opts, PH_PASTSOCKET); - applyopts(fd->stream.fd, opts, PH_FD); + fd->stream.fd2 = fd->stream.fd1; + fd->stream.fdtype = FDTYPE_SINGLE; + 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; salen = xiosetunix(&sa, filename, false, false); #if 0 - applyopts(fd->stream.fd, opts, PH_PREBIND); - applyopts(fd->stream.fd, opts, PH_BIND); + applyopts(fd->stream.fd1, opts, PH_PREBIND); + applyopts(fd->stream.fd1, opts, PH_BIND); 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", fd->fd, sockaddr_info(us, infobuff, sizeof(infobuff)), uslen, strerror(errno)); @@ -104,33 +115,33 @@ static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xio return STAT_RETRYLATER; } } - applyopts(fd->stream.fd, opts, PH_PASTBIND); + applyopts(fd->stream.fd1, opts, PH_PASTBIND); #endif /* 0 */ - applyopts(fd->stream.fd, opts, PH_CONNECT); - if ((result = Connect(fd->stream.fd, (struct sockaddr *)&sa, salen)) < 0) { + applyopts(fd->stream.fd1, opts, PH_CONNECT); + if ((result = Connect(fd->stream.fd1, (struct sockaddr *)&sa, salen)) < 0) { if (errno == EINPROGRESS) { 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)); } else if (errno == EPROTOTYPE && optsotype != SOCK_STREAM) { 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)); Info("assuming datagram socket"); - Close(fd->stream.fd); + Close(fd->stream.fd1); 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)); 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.fd, opts, PH_FD); + 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; 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); } else { 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)); return STAT_RETRYLATER; } } - if (fd->stream.howtoend == END_UNSPEC) { - fd->stream.howtoend = END_SHUTDOWN; - } + if (fd->stream.howtoshut == XIOSHUT_UNSPEC) + fd->stream.howtoshut = XIOSHUT_CLOSE; + if (fd->stream.howtoclose == XIOCLOSE_UNSPEC) + fd->stream.howtoclose = XIOCLOSE_CLOSE; - applyopts_fchown(fd->stream.fd, opts); - applyopts(fd->stream.fd, opts, PH_CONNECTED); - applyopts(fd->stream.fd, opts, PH_LATE); + applyopts_fchown(fd->stream.fd1, opts); + applyopts(fd->stream.fd1, opts, PH_CONNECTED); + applyopts(fd->stream.fd1, opts, PH_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", - fd->stream.fd, &us, uslen, strerror(errno)); + fd->stream.fd1, &us, uslen, strerror(errno)); } else { Notice1("successfully connected via %s", 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"); } #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 (Isatty(fd->stream.fd)) { - if (Tcgetattr(fd->stream.fd, &fd->stream.savetty) < 0) { + if (Isatty(fd->stream.fd1)) { + if (Tcgetattr(fd->stream.fd1, &fd->stream.savetty) < 0) { Warn2("cannot query current terminal settings on fd %d: %s", - fd->stream.fd, strerror(errno)); + fd->stream.fd1, strerror(errno)); } else { fd->stream.ttyvalid = true; } } #endif /* WITH_TERMIOS */ applyopts_named(filename, opts, PH_FD); - applyopts(fd->stream.fd, opts, PH_FD); - applyopts_cloexec(fd->stream.fd, opts); + applyopts(fd->stream.fd1, opts, PH_FD); + 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; if ((result = _xio_openlate(&fd->stream, opts)) < 0) diff --git a/xio-gopen.h b/xio-gopen.h index dff3084..2b51ef7 100644 --- a/xio-gopen.h +++ b/xio-gopen.h @@ -1,10 +1,11 @@ -/* $Id: xio-gopen.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001 */ +/* $Id: xio-gopen.h,v 1.4.2.1 2006/07/24 19:17:49 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_gopen_h_included #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) */ diff --git a/xio-ipapp.c b/xio-ipapp.c index b1fd5c3..d6a5c62 100644 --- a/xio-ipapp.c +++ b/xio-ipapp.c @@ -6,7 +6,7 @@ #include "xiosysincludes.h" -#if WITH_TCP || WITH_UDP +#if _WITH_TCP || _WITH_UDP #include "xioopen.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_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" */ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, 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); } - xfd->howtoend = END_SHUTDOWN; - if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; applyopts(-1, opts, PH_INIT); @@ -124,7 +122,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, } /* parent process */ Notice1("forked off child process "F_pid, pid); - Close(xfd->fd); + Close(xfd->fd1); /* with and without retry */ Nanosleep(&xfd->intervall, NULL); dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); @@ -214,10 +212,10 @@ int sockaddr_info((struct sockaddr *)them, *themlen, infobuff, sizeof(infobuff))); 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, const char *portname, int *pf, int ipproto, unsigned long res_opts0, @@ -271,7 +269,8 @@ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts, #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; applyopts(-1, opts, PH_INIT); @@ -293,6 +292,6 @@ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts, return result; 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 */ diff --git a/xio-listen.c b/xio-listen.c index 518291b..abcb152 100644 --- a/xio-listen.c +++ b/xio-listen.c @@ -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 1 - 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) { + if ((xfd->fd1 = Socket(pf, socktype, proto)) < 0) { Msg4(level, "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); 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->fd, opts, PH_BIND); - if (Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { - Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd, + applyopts(xfd->fd1, opts, PH_PREBIND); + applyopts(xfd->fd1, opts, PH_BIND); + if (Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) { + Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, strerror(errno)); - Close(xfd->fd); + Close(xfd->fd1); 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 fields that we want to know. */ salen = sizeof(sa); - if (Getsockname(xfd->fd, us, &uslen) < 0) { + if (Getsockname(xfd->fd1, us, &uslen) < 0) { 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 (us->sa_family == AF_UNIX) { /*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 */ retropt_int(opts, OPT_BACKLOG, &backlog); - if (Listen(xfd->fd, backlog) < 0) { - Error3("listen(%d, %d): %s", xfd->fd, backlog, strerror(errno)); + if (Listen(xfd->fd1, backlog) < 0) { + Error3("listen(%d, %d): %s", xfd->fd1, backlog, strerror(errno)); return STAT_RETRYLATER; } @@ -229,9 +207,9 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl do { /*? int level = E_ERROR;*/ 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) { - /*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 */ } if (errno == EINTR) { @@ -239,12 +217,12 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl } if (errno == ECONNABORTED) { Notice4("accept(%d, %p, {"F_Zu"}): %s", - xfd->fd, &sa, salen, strerror(errno)); + xfd->fd1, &sa, salen, strerror(errno)); continue; } Msg4(level, "accept(%d, %p, {"F_Zu"}): %s", - xfd->fd, &sa, salen, strerror(errno)); - Close(xfd->fd); + xfd->fd1, &sa, salen, strerror(errno)); + Close(xfd->fd1); return STAT_RETRYLATER; } while (true); 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, 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 ((pid = Fork()) < 0) { Msg1(level, "fork(): %s", strerror(errno)); - Close(xfd->fd); + Close(xfd->fd1); return STAT_RETRYLATER; } if (pid == 0) { /* child */ - if (Close(xfd->fd) < 0) { - Info2("close(%d): %s", xfd->fd, strerror(errno)); + if (Close(xfd->fd1) < 0) { + Info2("close(%d): %s", xfd->fd1, strerror(errno)); } - xfd->fd = ps; + xfd->fd1 = ps; #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); Info("still listening"); } else { - if (Close(xfd->fd) < 0) { - Info2("close(%d): %s", xfd->fd, strerror(errno)); + if (Close(xfd->fd1) < 0) { + Info2("close(%d): %s", xfd->fd1, strerror(errno)); } - xfd->fd = ps; + xfd->fd1 = ps; break; } } diff --git a/xio-nop.c b/xio-nop.c new file mode 100644 index 0000000..b9fc72a --- /dev/null +++ b/xio-nop.c @@ -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 */ + diff --git a/xio-nop.h b/xio-nop.h new file mode 100644 index 0000000..6ced7bf --- /dev/null +++ b/xio-nop.h @@ -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) */ diff --git a/xio-openssl.c b/xio-openssl.c index 4f8e98e..c396675 100644 --- a/xio-openssl.c +++ b/xio-openssl.c @@ -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); -/* description record for ssl connect */ -const struct addrdesc addr_openssl = { - "openssl", /* keyword for selecting this address type in xioopen calls +/* description record for inter-address ssl connect with 0 parameters */ +static const struct xioaddr_inter_desc xiointer_openssl_connect0 = { + XIOADDR_INTER, /* this is an embedded address (inter module) */ + "openssl-client", /* keyword for selecting this address type in xioopen calls (canonical or main name) */ - 3, /* data flow directions this address supports on API layer: - 1..read, 2..write, 3..both */ + 0, /* number of required parameters */ + 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.*/ + 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. 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 use the same xioopen_openssl function for slightly different address types. */ @@ -71,16 +100,53 @@ const struct addrdesc addr_openssl = { 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 -/* description record for ssl listen */ -const struct addrdesc addr_openssl_listen = { - "openssl-listen", /* keyword for selecting this address type in xioopen calls +/* description record for inter-address ssl listen */ +static const struct xioaddr_inter_desc xiointer_openssl_listen0 = { + XIOADDR_INTER, /* this is an embedded address (inter module) */ + "openssl-server", /* keyword for selecting this address type in xioopen calls (canonical or main name) */ - 3, /* data flow directions this address supports on API layer: - 1..read, 2..write, 3..both */ + 0, /* number of required parameters */ + 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.*/ + 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. 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 use the same xioopen_openssl_listen function for slightly different address types. */ @@ -91,6 +157,13 @@ const struct addrdesc addr_openssl_listen = { No trailing comma or semicolon! 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 */ /* both client and server */ @@ -153,7 +226,7 @@ static int { struct single *xfd = &xxfd->stream; struct opt *opts0 = NULL; - const char *hostname, *portname; + const char *hostname, *portname = NULL; int pf = PF_UNSPEC; int ipproto = IPPROTO_TCP; int socktype = SOCK_STREAM; @@ -165,7 +238,7 @@ static int bool needbind = false; bool lowport = false; int level; - SSL_CTX* ctx; + /*0 SSL_CTX* ctx;*/ bool opt_ver = true; /* verify peer certificate */ char *opt_cert = NULL; /* file name of client certificate */ int result; @@ -176,32 +249,62 @@ static int } xfd->flags |= XIO_DOESCONVERT; - if (argc != 3) { - Error1("%s: 2 parameters required", argv[0]); - return STAT_NORETRY; - } - hostname = argv[1]; - portname = argv[2]; + xfd->howtoshut = XIOSHUT_OPENSSL; + xfd->howtoclose = XIOCLOSE_CLOSE; - xfd->howtoend = END_SHUTDOWN; - if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; - applyopts(-1, opts, PH_INIT); + /* we support two forms of openssl-connect */ + if (argc == 3) { + hostname = argv[1]; + portname = argv[2]; + + /* a "terminal" form where we build a tcp connection to given host and + port */ + + applyopts_single(xfd, opts, PH_INIT); + 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; + + result = + _xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, + xfd->para.socket.ip.res_opts[1], + xfd->para.socket.ip.res_opts[0], + them, &themlen, us, &uslen, + &needbind, &lowport, &socktype); + 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); - retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert); - - result = - _xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert, &ctx); - if (result != STAT_OK) return STAT_NORETRY; - - result = - _xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, - xfd->para.socket.ip.res_opts[1], - xfd->para.socket.ip.res_opts[0], - them, &themlen, us, &uslen, - &needbind, &lowport, &socktype); - if (result != STAT_OK) return STAT_NORETRY; + } else { + Error1("%s: 0 or 2 parameters required", argv[0]); + return STAT_NORETRY; + } if (xioopts.logopt == 'm') { Info("starting connect loop, switching to syslog"); @@ -219,6 +322,8 @@ static int #endif /* WITH_RETRY */ level = E_ERROR; + /*!!! this belongs only to "old" openssl-connect form */ + if (portname) { /* this cannot fork because we retrieved fork option above */ result = _xioopen_connect(xfd, @@ -242,6 +347,7 @@ static int #endif /* WITH_RETRY */ default: return result; + } } /*! isn't this too early? */ @@ -249,14 +355,17 @@ static int 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) { case STAT_OK: break; #if WITH_RETRY case STAT_RETRYLATER: case STAT_RETRYNOW: 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); if (result == STAT_RETRYLATER) { Nanosleep(&xfd->intervall, NULL); @@ -297,7 +406,9 @@ static int } /* parent process */ 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); xfd->para.openssl.ssl = NULL; /* with and without retry */ @@ -383,7 +494,7 @@ static int addr_openssl */ { struct single *xfd = &xxfd->stream; - const char *portname; + const char *portname = NULL; struct opt *opts0 = NULL; union sockaddr_union us_sa, *us = &us_sa; socklen_t uslen = sizeof(us_sa); @@ -392,7 +503,7 @@ static int int ipproto = IPPROTO_TCP; /*! lowport? */ int level; - SSL_CTX* ctx; + /*0 SSL_CTX* ctx;*/ bool opt_ver = true; /* verify peer certificate - changed with 1.6.0 */ char *opt_cert = NULL; /* file name of server certificate */ int result; @@ -403,11 +514,6 @@ static int } xfd->flags |= XIO_DOESCONVERT; - if (argc != 2) { - Error1("%s: 1 parameter required", argv[0]); - return STAT_NORETRY; - } - #if WITH_IP4 && WITH_IP6 pf = xioopts.default_ip=='6'?PF_INET6:PF_INET; #elif WITH_IP6 @@ -415,33 +521,57 @@ static int #else pf = PF_INET; #endif - - portname = argv[1]; - xfd->howtoend = END_SHUTDOWN; - if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; - applyopts(-1, opts, PH_INIT); + if (argc == 2) { - retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert); - if (opt_cert == NULL) { - Warn("no certificate given; consider option \"cert\""); - } + portname = argv[1]; + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); - applyopts(-1, opts, PH_EARLY); + 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, &ctx); - if (result != STAT_OK) return STAT_NORETRY; + 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) + 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; + return STAT_NORETRY; + } + + } else if (argc == 1) { + if (xfd->fd1 < 0) { + Error("openssl-listen without 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_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert); + if (opt_cert == NULL) { + Warn("no certificate given; consider option \"cert\""); + } + + applyopts(-1, opts, PH_EARLY); + + result = + _xioopen_openssl_prepare(opts, xfd, true, &opt_ver, opt_cert, + &xfd->para.openssl.ctx); + if (result != STAT_OK) return STAT_NORETRY; + + } else { + Error1("%s: 1 parameter required", argv[0]); + return -1; } - xfd->addr = &addr_openssl_listen; xfd->dtype = XIODATA_OPENSSL; while (true) { /* loop over failed attempts */ @@ -453,17 +583,19 @@ static int #endif /* WITH_RETRY */ level = E_ERROR; - /* tcp listen; this can fork() for us; it only returns on error or on - successful establishment of tcp connection */ - result = _xioopen_listen(xfd, xioflags, - (struct sockaddr *)us, uslen, - opts, pf, socktype, IPPROTO_TCP, + if (portname) { + /* tcp listen; this can fork() for us; it only returns on error or on + successful establishment of tcp connection */ + result = _xioopen_listen(xfd, xioflags, + (struct sockaddr *)us, uslen, + opts, pf, socktype, IPPROTO_TCP, #if WITH_RETRY - (xfd->retry||xfd->forever)?E_INFO:E_ERROR + (xfd->retry||xfd->forever)?E_INFO:E_ERROR #else - E_ERROR + E_ERROR #endif /* WITH_RETRY */ - ); + ); + } /*! not sure if we should try again on retry/forever */ switch (result) { case STAT_OK: break; @@ -484,8 +616,8 @@ static int default: return result; } - - result = _xioopen_openssl_listen(xfd, opt_ver, ctx, level); + result = + _xioopen_openssl_listen(xfd, opt_ver, xfd->para.openssl.ctx, level); switch (result) { case STAT_OK: break; #if WITH_RETRY @@ -537,12 +669,11 @@ int _xioopen_openssl_listen(struct single *xfd, } /* assign the network connection to the SSL object */ - if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->fd) <= 0) { - if (ERR_peek_error() == 0) Msg(level, "SSL_set_fd() failed"); - while (err = ERR_get_error()) { - Msg2(level, "SSL_set_fd(, %d): %s", - xfd->fd, ERR_error_string(err, NULL)); - } + ret = xioSSL_set_fd(xfd, level); + if (ret != STAT_OK) { + sycSSL_free(xfd->para.openssl.ssl); + xfd->para.openssl.ssl = NULL; + return ret; } #if WITH_DEBUG @@ -634,7 +765,6 @@ int unsigned long err; int result; - xfd->addr = &addr_openssl; xfd->dtype = XIODATA_OPENSSL; retropt_bool(opts, OPT_OPENSSL_FIPS, &opt_fips); @@ -751,7 +881,7 @@ int if ((result = openssl_SSL_ERROR_SSL(E_ERROR, "SSL_CTX_load_verify_locations")) != STAT_OK) { - /*! free ctx */ + SSL_CTX_free(*ctx); *ctx = NULL; return STAT_RETRYLATER; } } @@ -963,14 +1093,33 @@ static int xioSSL_set_fd(struct single *xfd, int level) { unsigned long err; /* 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"); while (err = ERR_get_error()) { Msg2(level, "SSL_set_fd(, %d): %s", - xfd->fd, ERR_error_string(err, NULL)); + xfd->fd2, ERR_error_string(err, NULL)); } 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; } diff --git a/xio-openssl.h b/xio-openssl.h index 35bc6ac..4d1d2f7 100644 --- a/xio-openssl.h +++ b/xio-openssl.h @@ -10,8 +10,8 @@ #define SSLIO_BASE 0x53530000 /* "SSxx" */ #define SSLIO_MASK 0xffff0000 -extern const struct addrdesc addr_openssl; -extern const struct addrdesc addr_openssl_listen; +extern const union xioaddr_desc *xioaddrs_openssl_connect[]; +extern const union xioaddr_desc *xioaddrs_openssl_listen[]; extern const struct optdesc opt_openssl_cipherlist; extern const struct optdesc opt_openssl_method; diff --git a/xio-pipe.c b/xio-pipe.c index e4f6587..ea42657 100644 --- a/xio-pipe.c +++ b/xio-pipe.c @@ -12,16 +12,20 @@ #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_fifo_unnamed(xiofile_t *sock, struct opt *opts); +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_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(":") }; -const struct addrdesc addr_pipe = { "pipe", 3, xioopen_fifo, GROUP_FD|GROUP_NAMED|GROUP_OPEN|GROUP_FIFO, 0, 0, 0 HELP(":") }; - +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 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; int filedes[2]; int numleft; @@ -36,12 +40,13 @@ static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) { } /*0 Info2("pipe({%d,%d})", filedes[0], filedes[1]);*/ - sock->common.tag = XIO_TAG_RDWR; - sock->stream.dtype = XIODATA_PIPE; - sock->stream.fd = filedes[0]; - sock->stream.para.bipipe.fdout = filedes[1]; - applyopts_cloexec(sock->stream.fd, opts); - applyopts_cloexec(sock->stream.para.bipipe.fdout, opts); + sock->common.tag = XIO_TAG_RDWR; + sock->stream.dtype = XIODATA_2PIPE; + sock->stream.fd1 = filedes[0]; + sock->stream.fd2 = filedes[1]; + sock->stream.fdtype = FDTYPE_DOUBLE; + applyopts_cloexec(sock->stream.fd1, opts); + applyopts_cloexec(sock->stream.fd2, opts); /* one-time and input-direction options, no second application */ 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 */ - if ((result = applyopts(sock->stream.fd, opts, PH_ALL)) < 0) { + if ((result = applyopts(sock->stream.fd1, opts, PH_ALL)) < 0) { return result; } 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 */ - if ((result = applyopts(sock->stream.para.bipipe.fdout, opts2, PH_ALL)) < 0) + if ((result = applyopts(sock->stream.fd2, opts2, PH_ALL)) < 0) { return result; } @@ -75,7 +80,7 @@ static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) { /* 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]; int rw = (xioflags & XIO_ACCMODE); #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; 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; 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) { 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(fd->stream.fd, opts, PH_FD); - applyopts_cloexec(fd->stream.fd, opts); + applyopts(fd->stream.fd1, opts, PH_FD); + applyopts_cloexec(fd->stream.fd1, opts); return _xio_openlate(&fd->stream, opts); } diff --git a/xio-pipe.h b/xio-pipe.h index 1d72cf8..fc7efad 100644 --- a/xio-pipe.h +++ b/xio-pipe.h @@ -1,11 +1,11 @@ -/* $Id: xio-pipe.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001 */ +/* $Id: xio-pipe.h,v 1.4.2.1 2006/07/24 19:18:02 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_pipe_h_included #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); diff --git a/xio-progcall.c b/xio-progcall.c index aebde1c..1633253 100644 --- a/xio-progcall.c +++ b/xio-progcall.c @@ -6,6 +6,7 @@ #include "xiosysincludes.h" #include "xioopen.h" +#include "xiosigchld.h" #include "xio-process.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: 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, unsigned groups, 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_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"); @@ -125,15 +131,24 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ 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("option nofork is not allowed here"); + Error("nofork option is not allowed here"); /*!! free something */ return -1; } fd->flags |= XIO_DOESEXEC; - - free(*copts); - *copts = moveopts(popts, GROUP_ALL); +#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) { @@ -202,6 +217,13 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ # 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) { @@ -235,7 +257,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ 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) { Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno)); } else { @@ -283,8 +305,11 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ return STAT_RETRYLATER; } applyopts_cloexec(ptyfd, popts);/*!*/ - if (fd->howtoend = END_UNSPEC) { - fd->howtoend = END_CLOSE_KILL; + 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 */ @@ -292,7 +317,8 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ applyopts(ptyfd, popts, PH_LATE); 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 */ applyopts(ttyfd, *copts, PH_FD); @@ -301,13 +327,23 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ if (usepipes) { struct opt *popts2, *copts2; - if (rw == XIO_RDWR) + 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; } + } else { + rdpip[0] = rdpip[1] = -1; } /*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/ /* 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)); return STAT_RETRYLATER; } + } else { + wrpip[0] = wrpip[1] = -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[0], copts2, PH_FD); } - if (fd->howtoend == END_UNSPEC) { - fd->howtoend = END_CLOSE_KILL; - } /* this for parent, was after fork */ switch (rw) { - case XIO_RDONLY: fd->fd = rdpip[0]; break; - case XIO_WRONLY: fd->fd = wrpip[1]; break; - case XIO_RDWR: fd->fd = rdpip[0]; - fd->para.exec.fdout = wrpip[1]; + 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->fd, popts, PH_FD); - 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; } else { 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_PASTBIND); - if (fd->howtoend == END_UNSPEC) { - fd->howtoend = END_SHUTDOWN_KILL; + 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->fd = sv[0]; - applyopts(fd->fd, popts, PH_FD); - applyopts(fd->fd, popts, PH_LATE); + 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; } @@ -417,11 +473,18 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ 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 */ @@ -580,19 +643,23 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ return STAT_RETRYLATER; #endif + if (0) { + ; /* for canonical reasons */ #if HAVE_PTY - if (usepty) { + } else if (usepty) { if (Close(ttyfd) < 0) { Info2("close(%d): %s", ttyfd, strerror(errno)); } - } /*0 else*/ #endif /* HAVE_PTY */ -#if 0 - if (usepipes) { - } else { +#if 1 + } else if (usepipes) { + if (wrpip[0] >= 0) Close(wrpip[0]); + if (rdpip[1] >= 0) Close(rdpip[1]); + } else { /* socketpair() */ + Close(sv[1]); } #endif - fd->para.exec.pid = pid; + fd->child.pid = pid; if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; applyopts_signal(fd, popts); @@ -604,6 +671,639 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ 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 */ diff --git a/xio-progcall.h b/xio-progcall.h index d89ce31..3254a1c 100644 --- a/xio-progcall.h +++ b/xio-progcall.h @@ -1,5 +1,5 @@ /* $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 */ #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_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, unsigned groups, struct opt **opts diff --git a/xio-proxy.c b/xio-proxy.c index df673f2..5af454c 100644 --- a/xio-proxy.c +++ b/xio-proxy.c @@ -1,5 +1,5 @@ /* $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 */ /* this file contains the source for opening addresses of HTTP proxy CONNECT @@ -19,18 +19,29 @@ #define PROXYPORT "8080" -static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, - int xioflags, xiofile_t *fd, +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); + 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, + int dummy3); const struct optdesc opt_proxyport = { "proxyport", NULL, OPT_PROXYPORT, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC }; const struct optdesc opt_ignorecr = { "ignorecr", NULL, OPT_IGNORECR, 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 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(":::") }; +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("::") }; +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(":::") }; + +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" */ #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) { ssize_t result; do { - /* we need at least buflen bytes... */ - result = Read(xfd->fd, buff, buflen); + /* we need at least 16 bytes... */ + result = Read(xfd->fd1, buff, buflen); } while (result < 0 && errno == EINTR); /*! EAGAIN? */ if (result < 0) { Msg4(level, "read(%d, %p, "F_Zu"): %s", - xfd->fd, buff, buflen, strerror(errno)); + xfd->fd1, buff, buflen, strerror(errno)); return result; } if (result == 0) { @@ -75,46 +86,105 @@ static ssize_t #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) { - /* we expect the form: host:host:port */ struct single *xfd = &xxfd->stream; - struct opt *opts0 = NULL; 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, + unsigned groups, int dummy1, int dummy2, + int dummy3) { + /* we expect the form: host:host:port */ + struct single *xfd = &xxfd->stream; + 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 */ + bool dofork = false; + int socktype = SOCK_STREAM; + struct opt *opts0 = NULL; /* */ int pf = PF_UNSPEC; union sockaddr_union us_sa, *us = &us_sa; union sockaddr_union them_sa, *them = &them_sa; socklen_t uslen = sizeof(us_sa); socklen_t themlen = sizeof(them_sa); - const char *proxyname; char *proxyport = NULL; - const char *targetname, *targetport; int ipproto = IPPROTO_TCP; bool needbind = false; bool lowport = false; - int socktype = SOCK_STREAM; int level; int result; - if (argc != 4) { - Error1("%s: 3 parameters required", argv[0]); + if (xfd->fd1 >= 0) { + Error("xioopen_proxy_connect(): proxyname not allowed here"); return STAT_NORETRY; } proxyname = argv[1]; targetname = argv[2]; 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; applyopts(-1, opts, PH_INIT); retropt_int(opts, OPT_SO_TYPE, &socktype); 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 ((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, &needbind, &lowport, &socktype); if (result != STAT_OK) return result; - Notice4("opening connection to %s:%u via proxy %s:%s", proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport); @@ -146,11 +215,11 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, #endif /* WITH_RETRY */ level = E_ERROR; - result = - _xioopen_connect(xfd, - needbind?(struct sockaddr *)us:NULL, sizeof(*us), - (struct sockaddr *)them, themlen, - opts, pf, socktype, IPPROTO_TCP, lowport, level); + result = + _xioopen_connect(xfd, + needbind?(struct sockaddr *)us:NULL, sizeof(*us), + (struct sockaddr *)them, themlen, + opts, pf, socktype, IPPROTO_TCP, lowport, level); switch (result) { case STAT_OK: break; #if WITH_RETRY @@ -164,8 +233,9 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, default: return result; } - - applyopts(xfd->fd, opts, PH_ALL); + xfd->fdtype = FDTYPE_SINGLE; + applyopts(xfd->fd1, opts, PH_ALL); + /*!*/ if ((result = _xio_openlate(xfd, opts)) < 0) return result; @@ -212,7 +282,8 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, } /* parent process */ Notice1("forked off child process "F_pid, pid); - Close(xfd->fd); + Close(xfd->fd1); + Close(xfd->fd2); Nanosleep(&xfd->intervall, NULL); dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); 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 */ - Notice4("successfully connected to %s:%u via proxy %s:%s", - proxyvars->targetaddr, proxyvars->targetport, - proxyname, proxyport); + Notice2("successfully connected to %s:%u via proxy", + proxyvars->targetaddr, proxyvars->targetport); return 0; } @@ -275,6 +345,7 @@ int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, int _xioopen_proxy_connect(struct single *xfd, struct proxyvars *proxyvars, int level) { + int wfd; size_t offset; char request[CONNLEN]; char buff[BUFLEN+1]; @@ -286,6 +357,8 @@ int _xioopen_proxy_connect(struct single *xfd, int state; ssize_t sresult; + wfd = (xfd->fdtype == FDTYPE_SINGLE ? xfd->fd1 : xfd->fd2); + /* generate proxy request header - points to final target */ sprintf(request, "CONNECT %s:%u HTTP/1.0\r\n", proxyvars->targetaddr, proxyvars->targetport); @@ -295,13 +368,13 @@ int _xioopen_proxy_connect(struct single *xfd, Info1("sending \"%s\"", textbuff); /* write errors are assumed to always be hard errors, no retry */ do { - sresult = Write(xfd->fd, request, strlen(request)); + sresult = Write(wfd, request, strlen(request)); } while (sresult < 0 && errno == EINTR); if (sresult < 0) { Msg4(level, "write(%d, %p, "F_Zu"): %s", - xfd->fd, request, strlen(request), strerror(errno)); - if (Close(xfd->fd) < 0) { - Info2("close(%d): %s", xfd->fd, strerror(errno)); + wfd, request, strlen(request), strerror(errno)); + if (Close(wfd) < 0) { + Info2("close(%d): %s", xfd->fd2, strerror(errno)); } return STAT_RETRYLATER; } @@ -328,13 +401,13 @@ int _xioopen_proxy_connect(struct single *xfd, Info1("sending \"%s\\r\\n\"", header); *next++ = '\r'; *next++ = '\n'; *next++ = '\0'; do { - sresult = Write(xfd->fd, header, strlen(header)); + sresult = Write(wfd, header, strlen(header)); } while (sresult < 0 && errno == EINTR); if (sresult < 0) { Msg4(level, "write(%d, %p, "F_Zu"): %s", - xfd->fd, header, strlen(header), strerror(errno)); - if (Close(xfd->fd) < 0) { - Info2("close(%d): %s", xfd->fd, strerror(errno)); + xfd->fd2, header, strlen(header), strerror(errno)); + if (Close(wfd/*!*/) < 0) { + Info2("close(%d): %s", xfd->fd2, strerror(errno)); } return STAT_RETRYLATER; } @@ -344,7 +417,7 @@ int _xioopen_proxy_connect(struct single *xfd, Info("sending \"\\r\\n\""); do { - sresult = Write(xfd->fd, "\r\n", 2); + sresult = Write(wfd, "\r\n", 2); } while (sresult < 0 && errno == EINTR); /*! */ diff --git a/xio-proxy.h b/xio-proxy.h index bcaa054..cc9e852 100644 --- a/xio-proxy.h +++ b/xio-proxy.h @@ -1,5 +1,5 @@ -/* $Id: xio-proxy.h,v 1.6 2006/05/31 19:17:57 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2002-2006 */ +/* $Id: xio-proxy.h,v 1.6.2.1 2006/07/24 19:18:10 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2002-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #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_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, const char *targetname, const char *targetport); diff --git a/xio-pty.c b/xio-pty.c index c56f17e..7c44964 100644 --- a/xio-pty.c +++ b/xio-pty.c @@ -18,9 +18,18 @@ #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(":") }; + +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 }; #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 }; #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 */ int ptyfd = -1, ttyfd = -1; #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 */ char ptyname[MAXPTYNAMELEN]; char *tn = NULL; - char *linkname = NULL; bool opt_unlink_close = true; /* remove symlink afterwards */ bool wait_slave = false; /* true would be better for many platforms, but 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 */ struct timespec pollintv = { PTY_INTERVALL }; - xfd->stream.howtoend = END_CLOSE; - applyopts(-1, opts, PH_INIT); 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 */ - if (!retropt_string(opts, OPT_SYMBOLIC_LINK, &linkname)) { + if (linkname) { if (Unlink(linkname) < 0 && errno != ENOENT) { 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);/*!*/ xfd->stream.dtype = XIODATA_PTY; + xfd->stream.fdtype = FDTYPE_SINGLE; applyopts(ptyfd, opts, PH_FD); - xfd->stream.fd = ptyfd; + xfd->stream.fd1 = ptyfd; applyopts(ptyfd, opts, PH_LATE); if (applyopts_single(&xfd->stream, opts, PH_LATE) < 0) return -1; diff --git a/xio-pty.h b/xio-pty.h index 1d77414..0c93eff 100644 --- a/xio-pty.h +++ b/xio-pty.h @@ -1,11 +1,11 @@ -/* $Id: xio-pty.h,v 1.2 2004/10/24 13:49:53 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2002-2004 */ +/* $Id: xio-pty.h,v 1.2.2.1 2006/07/24 19:18:15 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2002-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_pty_h_included #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; #if HAVE_POLL diff --git a/xio-rawip.c b/xio-rawip.c index 187942f..bf1d3f5 100644 --- a/xio-rawip.c +++ b/xio-rawip.c @@ -34,31 +34,41 @@ static int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int pf, int socktype, int ipproto); - static int _xioopen_rawip_sendto(const char *hostname, const char *protname, struct opt *opts, int xioflags, 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("::") }; -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("::") }; -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(":") }; -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(":") }; +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("::") }; +const union xioaddr_desc *xioaddrs_rawip_sendto[] = { (union xioaddr_desc *)&xioaddr_rawip_sendto2, NULL }; +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("::") }; +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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_rawip_recv[] = { (union xioaddr_desc *)&xioaddr_rawip_recv1, NULL }; #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("::") }; -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("::") }; -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(":") }; -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(":") }; -#endif +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("::") }; +const union xioaddr_desc *xioaddrs_rawip4_sendto[] = { (union xioaddr_desc *)&xioaddr_rawip4_sendto2, NULL }; +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("::") }; +const union xioaddr_desc *xioaddrs_rawip4_datagram[] = { (union xioaddr_desc *)&xioaddr_rawip4_datagram2, NULL }; +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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_rawip4_recv[] = { (union xioaddr_desc *)&xioaddr_rawip4_recv1, NULL }; +#endif /* IWITH_IP4 */ #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("::") }; -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("::") }; -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(":") }; -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(":") }; -#endif - +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("::") }; +const union xioaddr_desc *xioaddrs_rawip6_sendto[] = { (union xioaddr_desc *)&xioaddr_rawip6_sendto2, NULL }; +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("::") }; +const union xioaddr_desc *xioaddrs_rawip6_datagram[] = { (union xioaddr_desc *)&xioaddr_rawip6_datagram2, NULL }; +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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_rawip6_recv[] = { (union xioaddr_desc *)&xioaddr_rawip6_recv1, NULL }; +#endif /* WITH_IP6 */ /* we expect the form: host:protocol */ /* struct sockaddr_in sa;*/ @@ -106,7 +116,6 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname, /*return STAT_NORETRY;*/ } - xfd->howtoend = END_SHUTDOWN; retropt_int(opts, OPT_SO_TYPE, &socktype); /* ...res_opts[] */ @@ -128,6 +137,7 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname, uslen = socket_init(pf, &us); + xfd->fdtype = FDTYPE_SINGLE; xfd->dtype = XIODATA_RECVFROM_SKIPIP; 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); /*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_socket_pf(opts, &pf); @@ -235,6 +246,7 @@ int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts, needbind = true; } + xfd->stream.fdtype = FDTYPE_SINGLE; xfd->stream.dtype = XIODATA_RECVFROM_SKIPIP_ONE; if ((result = _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.fdtype = FDTYPE_SINGLE; xfd->stream.dtype = XIODATA_RECV_SKIPIP; result = _xioopen_dgram_recv(&xfd->stream, xioflags, NULL/*&us.soa*/, uslen, opts, pf, socktype, ipproto, E_ERROR); diff --git a/xio-rawip.h b/xio-rawip.h index 0c57a02..4de5688 100644 --- a/xio-rawip.h +++ b/xio-rawip.h @@ -5,17 +5,17 @@ #ifndef __xio_rawip_h_included #define __xio_rawip_h_included 1 -extern const struct addrdesc addr_rawip_sendto; -extern const struct addrdesc addr_rawip_datagram; -extern const struct addrdesc addr_rawip_recvfrom; -extern const struct addrdesc addr_rawip_recv; -extern const struct addrdesc addr_rawip4_sendto; -extern const struct addrdesc addr_rawip4_datagram; -extern const struct addrdesc addr_rawip4_recvfrom; -extern const struct addrdesc addr_rawip4_recv; -extern const struct addrdesc addr_rawip6_sendto; -extern const struct addrdesc addr_rawip6_datagram; -extern const struct addrdesc addr_rawip6_recvfrom; -extern const struct addrdesc addr_rawip6_recv; +extern const union xioaddr_desc *xioaddrs_rawip_sendto[]; +extern const union xioaddr_desc *xioaddrs_rawip_datagram[]; +extern const union xioaddr_desc *xioaddrs_rawip_recvfrom[]; +extern const union xioaddr_desc *xioaddrs_rawip_recv[]; +extern const union xioaddr_desc *xioaddrs_rawip4_sendto[]; +extern const union xioaddr_desc *xioaddrs_rawip4_datagram[]; +extern const union xioaddr_desc *xioaddrs_rawip4_recvfrom[]; +extern const union xioaddr_desc *xioaddrs_rawip4_recv[]; +extern const union xioaddr_desc *xioaddrs_rawip6_sendto[]; +extern const union xioaddr_desc *xioaddrs_rawip6_datagram[]; +extern const union xioaddr_desc *xioaddrs_rawip6_recvfrom[]; +extern const union xioaddr_desc *xioaddrs_rawip6_recv[]; #endif /* !defined(__xio_rawip_h_included) */ diff --git a/xio-readline.c b/xio-readline.c index 584543f..8c27ad1 100644 --- a/xio-readline.c +++ b/xio-readline.c @@ -30,8 +30,13 @@ static int xioopen_readline(int argc, const char *argv[], struct opt *opts, int dummy1, int dummy2, int dummy3); -const struct addrdesc addr_readline = { - "readline", 3, xioopen_readline, GROUP_FD|GROUP_TERMIOS|GROUP_READLINE, 0, 0, 0 HELP(NULL) }; +static const struct xioaddr_endpoint_desc xioendpoint_readline0 = { + 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_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); - xfd->stream.fd = 0; /* stdin */ - xfd->stream.howtoend = END_NONE; + xfd->stream.fd1 = 0; /* stdin */ + xfd->stream.howtoclose = XIOCLOSE_READLINE; xfd->stream.dtype = XIODATA_READLINE; + xfd->stream.fdtype = FDTYPE_SINGLE; #if WITH_TERMIOS - if (Isatty(xfd->stream.fd)) { - if (Tcgetattr(xfd->stream.fd, &xfd->stream.savetty) < 0) { + if (Isatty(xfd->stream.fd1)) { + if (Tcgetattr(xfd->stream.fd1, &xfd->stream.savetty) < 0) { Warn2("cannot query current terminal settings on fd %d. %s", - xfd->stream.fd, strerror(errno)); + xfd->stream.fd1, strerror(errno)); } else { 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; 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(); 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) { Read_history(xfd->stream.para.readline.history_file); } - xiotermios_clrflag(xfd->stream.fd, 3, ICANON); - xiotermios_clrflag(xfd->stream.fd, 3, ECHO); + xiotermios_clrflag(xfd->stream.fd1, 3, ICANON); + xiotermios_clrflag(xfd->stream.fd1, 3, ECHO); return _xio_openlate(&xfd->stream, opts); } @@ -141,40 +147,40 @@ ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) { readline */ struct termios saveterm, setterm; *pipe->para.readline.dynend = '\0'; - Tcgetattr(pipe->fd, &saveterm); /*! error */ + Tcgetattr(pipe->fd1, &saveterm); /*! error */ setterm = saveterm; setterm.c_lflag |= ICANON; - Tcsetattr(pipe->fd, TCSANOW, &setterm); /*!*/ + Tcsetattr(pipe->fd1, TCSANOW, &setterm); /*!*/ do { - bytes = Read(pipe->fd, buff, bufsiz); + bytes = Read(pipe->fd1, buff, bufsiz); } while (bytes < 0 && errno == EINTR); if (bytes < 0) { _errno = errno; Error4("read(%d, %p, "F_Zu"): %s", - pipe->fd, buff, bufsiz, strerror(_errno)); + pipe->fd1, buff, bufsiz, strerror(_errno)); errno = _errno; return -1; } setterm.c_lflag &= ~ICANON; - Tcgetattr(pipe->fd, &setterm); /*! error */ - Tcsetattr(pipe->fd, TCSANOW, &saveterm); /*!*/ + Tcgetattr(pipe->fd1, &setterm); /*! error */ + Tcsetattr(pipe->fd1, TCSANOW, &saveterm); /*!*/ pipe->para.readline.dynend = pipe->para.readline.dynprompt; - /*Write(pipe->fd, "\n", 1);*/ /*!*/ + /*Write(pipe->fd1, "\n", 1);*/ /*!*/ return bytes; } #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) { /* we must carriage return, because readline will first print the prompt */ ssize_t writt; do { - writt = Write(pipe->fd, "\r", 1); + writt = Write(pipe->fd1, "\r", 1); } while (writt < 0 && errno == EINTR); if (writt < 0) { Warn2("write(%d, \"\\r\", 1): %s", - pipe->fd, strerror(errno)); + pipe->fd1, strerror(errno)); } else if (writt < 1) { 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) { return 0; /* EOF */ } - xiotermios_clrflag(pipe->fd, 3, ECHO); + xiotermios_clrflag(pipe->fd1, 3, ECHO); Add_history(line); bytes = strlen(line); strncpy(buff, line, bufsiz); diff --git a/xio-readline.h b/xio-readline.h index 921d605..16e006d 100644 --- a/xio-readline.h +++ b/xio-readline.h @@ -1,11 +1,11 @@ -/* $Id: xio-readline.h,v 1.4 2003/12/23 21:38:59 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2002, 2003 */ +/* $Id: xio-readline.h,v 1.4.2.1 2006/07/24 19:18:24 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2002-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_readline_h_included #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_prompt; diff --git a/xio-socket.c b/xio-socket.c index c9b3d3e..c2e46cb 100644 --- a/xio-socket.c +++ b/xio-socket.c @@ -9,6 +9,7 @@ #if _WITH_SOCKET #include "xioopen.h" +#include "xiosigchld.h" #include "xio-socket.h" #include "xio-named.h" #if WITH_IP4 @@ -144,20 +145,21 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, int _errno; int result; - if ((xfd->fd = Socket(pf, stype, proto)) < 0) { + if ((xfd->fd1 = Socket(pf, stype, proto)) < 0) { Msg4(level, "socket(%d, %d, %d): %s", pf, stype, proto, strerror(errno)); return STAT_RETRYLATER; } + xfd->fdtype = FDTYPE_SINGLE; applyopts_offset(xfd, opts); - applyopts(xfd->fd, opts, PH_PASTSOCKET); - applyopts(xfd->fd, opts, PH_FD); + applyopts(xfd->fd1, opts, PH_PASTSOCKET); + applyopts(xfd->fd1, opts, PH_FD); - applyopts_cloexec(xfd->fd, opts); + applyopts_cloexec(xfd->fd1, opts); - applyopts(xfd->fd, opts, PH_PREBIND); - applyopts(xfd->fd, opts, PH_BIND); + applyopts(xfd->fd1, opts, PH_PREBIND); + applyopts(xfd->fd1, opts, PH_BIND); #if WITH_TCP || WITH_UDP if (alt) { union sockaddr_union sin, *sinp; @@ -214,13 +216,13 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, problem = false; do { /* loop over lowport bind() attempts */ *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, - "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)), sizeof(*sinp), strerror(errno)); if (errno != EADDRINUSE) { - Close(xfd->fd); + Close(xfd->fd1); return STAT_RETRYLATER; } } else { @@ -230,7 +232,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, if (i == N) { Msg(level, "no low port available"); /*errno = EADDRINUSE; still assigned */ - Close(xfd->fd); + Close(xfd->fd1); return STAT_RETRYLATER; } } while (i != N); @@ -238,31 +240,31 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, #endif /* WITH_TCP || WITH_UDP */ if (us) { - if (Bind(xfd->fd, us, uslen) < 0) { + if (Bind(xfd->fd1, us, uslen) < 0) { 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)); - Close(xfd->fd); + Close(xfd->fd1); 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 || xfd->para.socket.connect_timeout.tv_usec != 0) { - fcntl_flags = Fcntl(xfd->fd, F_GETFL); - Fcntl_l(xfd->fd, F_SETFL, fcntl_flags|O_NONBLOCK); + fcntl_flags = Fcntl(xfd->fd1, F_GETFL); + 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; 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", - xfd->fd, &la.soa, lalen, strerror(errno)); + xfd->fd1, &la.soa, lalen, strerror(errno)); } errno = _errno; if (result < 0) { @@ -273,15 +275,15 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, fd_set readfds, writefds, exceptfds; int result; 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)); timeout = xfd->para.socket.connect_timeout; 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 = - Select(xfd->fd+1, &readfds, &writefds, &exceptfds, &timeout); + Select(xfd->fd1+1, &readfds, &writefds, &exceptfds, &timeout); 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; } if (result == 0) { @@ -290,26 +292,26 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, strerror(ETIMEDOUT)); return STAT_RETRYLATER; } - if (FD_ISSET(xfd->fd, &readfds)) { + if (FD_ISSET(xfd->fd1, &readfds)) { #if 0 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", sockaddr_info(them, infobuff, sizeof(infobuff)), strerror(errno)); #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", - xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), - themlen, strerror(errno)); + xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), + themlen, strerror(errno)); #endif return STAT_RETRYLATER; } /* otherwise OK */ - Fcntl_l(xfd->fd, F_SETFL, fcntl_flags); + Fcntl_l(xfd->fd1, F_SETFL, fcntl_flags); } else { 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)); } } 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 */ int _errno = errno; 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)); #if 0 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); #endif /*!!! and remove bind socket */ - Close(xfd->fd); xfd->fd = -1; + Close(xfd->fd1); xfd->fd1 = -1; errno = _errno; return -1; } else { 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)); - Close(xfd->fd); + Close(xfd->fd1); return STAT_RETRYLATER; } } - applyopts_fchown(xfd->fd, opts); - applyopts(xfd->fd, opts, PH_CONNECTED); - applyopts(xfd->fd, opts, PH_LATE); - + applyopts_fchown(xfd->fd1, opts); + applyopts(xfd->fd1, opts, PH_CONNECTED); + applyopts(xfd->fd1, opts, PH_LATE); Notice1("successfully connected from local address %s", 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 */ Notice1("forked off child process "F_pid, pid); - Close(xfd->fd); + Close(xfd->fd1); /* with and without retry */ Nanosleep(&xfd->intervall, NULL); 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); char infobuff[256]; - if ((xfd->fd = Socket(pf, socktype, ipproto)) < 0) { + if ((xfd->fd1 = Socket(pf, socktype, ipproto)) < 0) { Msg4(level, "socket(%d, %d, %d): %s", pf, socktype, ipproto, strerror(errno)); return STAT_RETRYLATER; @@ -466,36 +467,36 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */ applyopts_offset(xfd, opts); applyopts_single(xfd, opts, PH_PASTSOCKET); - applyopts(xfd->fd, opts, PH_PASTSOCKET); - applyopts(xfd->fd, opts, PH_FD); + applyopts(xfd->fd1, opts, PH_PASTSOCKET); + applyopts(xfd->fd1, opts, PH_FD); - applyopts_cloexec(xfd->fd, opts); + applyopts_cloexec(xfd->fd1, opts); - applyopts(xfd->fd, opts, PH_PREBIND); - applyopts(xfd->fd, opts, PH_BIND); + applyopts(xfd->fd1, opts, PH_PREBIND); + applyopts(xfd->fd1, opts, PH_BIND); 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", - 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)); - Close(xfd->fd); + Close(xfd->fd1); 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", - xfd->fd, &la.soa, lalen, strerror(errno)); + xfd->fd1, &la.soa, lalen, strerror(errno)); } - applyopts_fchown(xfd->fd, opts); - applyopts(xfd->fd, opts, PH_CONNECTED); - applyopts(xfd->fd, opts, PH_LATE); + applyopts_fchown(xfd->fd1, opts); + applyopts(xfd->fd1, opts, PH_CONNECTED); + applyopts(xfd->fd1, opts, PH_LATE); /* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */ Notice1("successfully prepared local socket %s", @@ -577,24 +578,24 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, } #endif /* 1 */ - if ((xfd->fd = Socket(pf, socktype, proto)) < 0) { + if ((xfd->fd1 = Socket(pf, socktype, proto)) < 0) { Msg4(level, "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); return STAT_RETRYLATER; } 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->fd, opts, PH_BIND); - if ((us != NULL) && Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { - Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd, + applyopts(xfd->fd1, opts, PH_PREBIND); + applyopts(xfd->fd1, opts, PH_BIND); + if ((us != NULL) && Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) { + Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, strerror(errno)); - Close(xfd->fd); + Close(xfd->fd1); return STAT_RETRYLATER; } @@ -604,7 +605,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, } #endif - applyopts(xfd->fd, opts, PH_PASTBIND); + applyopts(xfd->fd1, opts, PH_PASTBIND); #if WITH_UNIX if (pf == AF_UNIX && us != NULL) { /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ @@ -688,7 +689,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, if (drop) { char *dummy[2]; - Recv(xfd->fd, dummy, sizeof(dummy), 0); + Recv(xfd->fd1, dummy, sizeof(dummy), 0); drop = true; } @@ -702,8 +703,8 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, Notice1("receiving IP protocol %u", proto); } FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt); - FD_SET(xfd->fd, &in); - if (Select(xfd->fd+1, &in, &out, &expt, NULL) > 0) { + FD_SET(xfd->fd1, &in); + if (Select(xfd->fd1+1, &in, &out, &expt, NULL) > 0) { break; } @@ -711,12 +712,12 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, continue; } - Msg2(level, "select(, {%d}): %s", xfd->fd, strerror(errno)); - Close(xfd->fd); + Msg2(level, "select(, {%d}): %s", xfd->fd1, strerror(errno)); + Close(xfd->fd1); return STAT_RETRYLATER; } while (true); - if (xiogetpacketsrc(xfd->fd, pa, &palen) < 0) { + if (xiogetpacketsrc(xfd->fd1, pa, &palen) < 0) { return STAT_RETRYLATER; } @@ -727,16 +728,16 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, if (xiocheckpeer(xfd, pa, la) < 0) { /* drop packet */ char buff[512]; - Recv(xfd->fd, buff, sizeof(buff), 0); + Recv(xfd->fd1, buff, sizeof(buff), 0); continue; } Info1("permitting packet from %s", sockaddr_info((struct sockaddr *)pa, palen, 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->salen = palen; @@ -758,7 +759,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, if ((pid = Fork()) < 0) { Msg1(level, "fork(): %s", strerror(errno)); - Close(xfd->fd); + Close(xfd->fd1); Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL); 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 ((xfd->fd = Socket(pf, socktype, proto)) < 0) { + if ((xfd->fd1 = Socket(pf, socktype, proto)) < 0) { Msg4(level, "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); return STAT_RETRYLATER; } 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->fd, opts, PH_BIND); - if ((us != NULL) && Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { - Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd, + applyopts(xfd->fd1, opts, PH_PREBIND); + applyopts(xfd->fd1, opts, PH_BIND); + if ((us != NULL) && Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) { + Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, strerror(errno)); - Close(xfd->fd); + Close(xfd->fd1); return STAT_RETRYLATER; } @@ -857,7 +858,7 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags, } #endif - applyopts(xfd->fd, opts, PH_PASTBIND); + applyopts(xfd->fd1, opts, PH_PASTBIND); #if WITH_UNIX if (pf == AF_UNIX && us != NULL) { /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ diff --git a/xio-socket.h b/xio-socket.h index 1bccf1f..422a906 100644 --- a/xio-socket.h +++ b/xio-socket.h @@ -1,5 +1,5 @@ /* $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 */ #ifndef __xio_socket_h_included diff --git a/xio-socks.c b/xio-socks.c index 8e990de..4bdfde2 100644 --- a/xio-socks.c +++ b/xio-socks.c @@ -1,5 +1,5 @@ /* $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 */ /* 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_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(":::") }; +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("::") }; +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(":::") }; -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(":::") }; +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("::") }; +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(":::") }; + +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, int xioflags, xiofile_t *xxfd, 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 */ struct single *xfd = &xxfd->stream; struct opt *opts0 = NULL; - const char *sockdname; char *socksport; + const char *sockdname; char *sockdport; const char *targetname, *targetport; int pf = PF_UNSPEC; 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 lowport = false; unsigned char buff[BUFF_LEN]; - struct socks4 *sockhead = (struct socks4 *)buff; + struct socks4request *sockhead = (struct socks4request *)buff; size_t buflen = sizeof(buff); int socktype = SOCK_STREAM; int level; int result; - if (argc != 4) { - Error1("%s: 3 parameters required", argv[0]); + if (argc < 3 || argc > 4) { + Warn("syntax 1 (terminal): socks-connect:::"); + Error("syntax 2 (inter): socks-connect::"); return STAT_NORETRY; } - sockdname = argv[1]; - targetname = argv[2]; - targetport = argv[3]; - xfd->howtoend = END_SHUTDOWN; + 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; + } + sockdname = argv[1]; + targetname = argv[2]; + targetport = argv[3]; + } + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; 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); - 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 (xfd->fd2 < 0) { result = - _xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport, + _xioopen_ipapp_prepare(opts, &opts0, sockdname, sockdport, &pf, ipproto, xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[0], them, &themlen, us, &uslen, &needbind, &lowport, &socktype); + if (result != STAT_OK) return result; Notice5("opening connection to %s:%u via socks4 server %s:%s as user \"%s\"", targetname, 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 */ @@ -123,6 +159,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts return result; } + if (xfd->fd2 < 0) { /* this cannot fork because we retrieved fork option above */ result = _xioopen_connect (xfd, @@ -142,8 +179,14 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts default: 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) return result; @@ -190,7 +233,8 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts } /* parent process */ Notice1("forked off child process "F_pid, pid); - Close(xfd->fd); + Close(xfd->fd1); + Close(xfd->fd2); Nanosleep(&xfd->intervall, NULL); dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); 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; char *userid; @@ -247,7 +291,7 @@ int _xioopen_socks4_connect0(struct single *xfd, const char *hostname, /* socks target host */ int socks4a, - struct socks4 *sockhead, + struct socks4request *sockhead, ssize_t *headlen, /* get available space, return used length*/ int level) { @@ -294,15 +338,18 @@ int /* perform socks4 client dialog on existing FD. Called within fork/retry loop, after connect() */ int _xioopen_socks4_connect(struct single *xfd, - struct socks4 *sockhead, + struct socks4request *sockhead, size_t headlen, int level) { ssize_t bytes; + int wfd; int result; unsigned char buff[SIZEOF_STRUCT_SOCKS4]; - struct socks4 *replyhead = (struct socks4 *)buff; + struct socks4head *replyhead = (struct socks4head *)buff; char *destdomname = NULL; + wfd = (xfd->fdtype == FDTYPE_SINGLE ? xfd->fd1 : xfd->fd2); + /* send socks header (target addr+port, +auth) */ #if WITH_MSGLEVEL <= E_INFO if (ntohl(sockhead->dest) <= 0x000000ff) { @@ -329,13 +376,16 @@ int _xioopen_socks4_connect(struct single *xfd, } #endif /* WITH_MSGLEVEL <= E_DEBUG */ do { - result = Write(xfd->fd, sockhead, headlen); + result = Write(wfd, sockhead, headlen); } while (result < 0 && errno == EINTR); if (result < 0) { Msg4(level, "write(%d, %p, "F_Zu"): %s", - xfd->fd, sockhead, headlen, strerror(errno)); - if (Close(xfd->fd) < 0) { - Info2("close(%d): %s", xfd->fd, strerror(errno)); + wfd, sockhead, headlen, strerror(errno)); + if (Close(wfd) < 0) { + 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 */ } @@ -345,20 +395,26 @@ int _xioopen_socks4_connect(struct single *xfd, while (bytes >= 0) { /* loop over answer chunks until complete or error */ /* receive socks answer */ 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); if (result < 0) { 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)); - if (Close(xfd->fd) < 0) { - Info2("close(%d): %s", xfd->fd, strerror(errno)); + if (Close(xfd->fd1) < 0) { + Info2("close(%d): %s", xfd->fd1, strerror(errno)); + } + if (Close(wfd) < 0) { + Info2("close(%d): %s", wfd, strerror(errno)); } } if (result == 0) { Msg(level, "read(): EOF during read of socks reply, peer might not be a socks4 server"); - if (Close(xfd->fd) < 0) { - Info2("close(%d): %s", xfd->fd, strerror(errno)); + if (Close(xfd->fd1) < 0) { + Info2("close(%d): %s", xfd->fd1, strerror(errno)); + } + if (Close(wfd) < 0) { + Info2("close(%d): %s", wfd, strerror(errno)); } return STAT_RETRYLATER; } diff --git a/xio-socks.h b/xio-socks.h index 5b97b11..fa312a2 100644 --- a/xio-socks.h +++ b/xio-socks.h @@ -1,36 +1,37 @@ -/* $Id: xio-socks.h,v 1.6 2004/06/06 19:03:28 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001-2004 */ +/* $Id: xio-socks.h,v 1.6.2.1 2006/07/24 19:18:30 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_socks_h_included #define __xio_socks_h_included 1 -struct socks4 { +#define SIZEOF_STRUCT_SOCKS4 sizeof(struct socks4head) + +struct socks4request { uint8_t version; uint8_t action; uint16_t port; uint32_t dest; 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_socksuser; -extern const struct addrdesc addr_socks4_connect; -extern const struct addrdesc addr_socks4a_connect; +extern const union xioaddr_desc *xioaddrs_socks4_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 _xioopen_socks4_connect0(struct single *xfd, const char *hostname, /* socks target host */ int socks4a, - struct socks4 *sockhead, + struct socks4request *sockhead, ssize_t *headlen, /* get available space, return used length*/ int level); extern int _xioopen_socks4_connect(struct single *xfd, - struct socks4 *sockhead, + struct socks4request *sockhead, size_t headlen, int level); diff --git a/xio-socks5.c b/xio-socks5.c new file mode 100644 index 0000000..ac76100 --- /dev/null +++ b/xio-socks5.c @@ -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("::") }; +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::"); /*! 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 */ + diff --git a/xio-socks5.h b/xio-socks5.h new file mode 100644 index 0000000..173318a --- /dev/null +++ b/xio-socks5.h @@ -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) */ diff --git a/xio-stdio.c b/xio-stdio.c index 64cc4ee..ae172f6 100644 --- a/xio-stdio.c +++ b/xio-stdio.c @@ -1,5 +1,5 @@ /* $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 */ /* 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 changed parsing mechanism does not allow us to check the type of FD before 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) }; -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) }; -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) }; -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_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) }; +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) }; +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) }; +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. generate a dual address. */ int xioopen_stdio_bi(xiofile_t *sock) { 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; - if (xioopen_makedual(sock) < 0) { - return -1; - } - - 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; + sock->stream.fd1 = 0 /*stdin*/; + sock->stream.fd2 = 1 /*stdout*/; + sock->stream.fdtype = FDTYPE_DOUBLE; #if WITH_TERMIOS - if (Isatty(sock->dual.stream[0]->fd)) { - if (Tcgetattr(sock->dual.stream[0]->fd, - &sock->dual.stream[0]->savetty) + if (Isatty(sock->stream.fd1)) { + if (Tcgetattr(sock->stream.fd1, + &sock->stream.savetty) < 0) { Warn2("cannot query current terminal settings on fd %d: %s", - sock->dual.stream[0]->fd, strerror(errno)); + sock->stream.fd1, strerror(errno)); } else { - sock->dual.stream[0]->ttyvalid = true; + sock->stream.ttyvalid = true; } } - if (Isatty(sock->dual.stream[1]->fd)) { - if (Tcgetattr(sock->dual.stream[1]->fd, - &sock->dual.stream[1]->savetty) + if (Isatty(sock->stream.fd2)) { + if (Tcgetattr(sock->stream.fd2, + &sock->stream.savetty) < 0) { Warn2("cannot query current terminal settings on fd %d: %s", - sock->dual.stream[1]->fd, strerror(errno)); + + sock->stream.fd2, strerror(errno)); } else { - sock->dual.stream[1]->ttyvalid = true; + sock->stream.ttyvalid = true; } } #endif /* WITH_TERMIOS */ @@ -71,7 +73,7 @@ int xioopen_stdio_bi(xiofile_t *sock) { applyopts(-1, sock->stream.opts, PH_INIT); /* 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 */ 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 */ - if ((result = applyopts(sock->dual.stream[0]->fd, opts1, PH_ALL)) < 0) { + if ((result = applyopts(sock->stream.fd1, opts1, PH_ALL)) < 0) { return result; } - if ((result = _xio_openlate(sock->dual.stream[0], opts1)) < 0) { + if ((result = _xio_openlate(&sock->stream, opts1)) < 0) { return result; } @@ -99,14 +101,14 @@ int xioopen_stdio_bi(xiofile_t *sock) { return -1; } /* 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; } - if ((result = _xio_openlate(sock->dual.stream[1], opts2)) < 0) { + if ((result = _xio_openlate(&sock->stream, opts2)) < 0) { return result; } - if ((result = _xio_openlate(sock->dual.stream[1], optspr)) < 0) { + if ((result = _xio_openlate(&sock->stream, optspr)) < 0) { 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", &("stdin\0\0\0stdout"[rw<<3]), 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. @@ -145,6 +147,6 @@ static int xioopen_stdfd(int argc, const char *argv[], struct opt *opts, int xio Notice2("using %s for %s", &("stdin\0\0\0stdout\0\0stderr"[fd<<3]), 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 */ diff --git a/xio-stdio.h b/xio-stdio.h index b75c17b..e70f160 100644 --- a/xio-stdio.h +++ b/xio-stdio.h @@ -1,17 +1,16 @@ -/* $Id: xio-stdio.h,v 1.5 2006/02/08 19:47:03 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001-2006 */ +/* $Id: xio-stdio.h,v 1.5.2.1 2006/07/24 19:18:35 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_stdio_h_included #define __xio_stdio_h_included 1 - extern int xioopen_stdio_bi(xiofile_t *sock); -extern const struct addrdesc addr_stdio; -extern const struct addrdesc addr_stdin; -extern const struct addrdesc addr_stdout; -extern const struct addrdesc addr_stderr; +extern const union xioaddr_desc *xioaddrs_stdio[]; +extern const union xioaddr_desc *xioaddrs_stdin[]; +extern const union xioaddr_desc *xioaddrs_stdout[]; +extern const union xioaddr_desc *xioaddrs_stderr[]; #endif /* !defined(__xio_stdio_h_included) */ diff --git a/xio-system.c b/xio-system.c index 3297870..ced0396 100644 --- a/xio-system.c +++ b/xio-system.c @@ -1,5 +1,5 @@ -/* $Id: xio-system.c,v 1.13 2006/03/21 20:53:38 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001-2006 */ +/* $Id: xio-system.c,v 1.13.2.1 2006/07/24 19:18:36 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ /* 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 ); -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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_system[] = { + (union xioaddr_desc *)&xioendpoint_system1, + NULL +}; static int xioopen_system(int argc, const char *argv[], struct opt *opts, int xioflags, /* XIO_RDONLY etc. */ @@ -34,7 +38,7 @@ static int xioopen_system(int argc, const char *argv[], struct opt *opts, int result; 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) { /* child */ int numleft; diff --git a/xio-system.h b/xio-system.h index 31f3fce..6668d55 100644 --- a/xio-system.h +++ b/xio-system.h @@ -1,10 +1,10 @@ -/* $Id: xio-system.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001 */ +/* $Id: xio-system.h,v 1.4.2.1 2006/07/24 19:18:38 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_system_h_included #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) */ diff --git a/xio-tcp.c b/xio-tcp.c index 24fa5ae..bed01af 100644 --- a/xio-tcp.c +++ b/xio-tcp.c @@ -1,5 +1,5 @@ -/* $Id: xio-tcp.c,v 1.24 2006/07/13 06:48:47 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001-2006 */ +/* $Id: xio-tcp.c,v 1.24.2.1 2006/07/24 19:18:39 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ /* this file contains the source for TCP related functions and options */ @@ -17,23 +17,29 @@ /****** TCP addresses ******/ #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("::") }; +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("::") }; +const union xioaddr_desc *xioaddrs_tcp_connect[] = { (union xioaddr_desc *)&xioendpoint_tcp_connect2, NULL }; #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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_tcp_listen[] = { (union xioaddr_desc *)&xioendpoint_tcp_listen1, NULL }; #endif #endif #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("::") }; +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("::") }; +const union xioaddr_desc *xioaddrs_tcp4_connect[] = { (union xioaddr_desc *)&xioendpoint_tcp4_connect2, NULL }; #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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_tcp4_listen[] = { (union xioaddr_desc *)&xioendpoint_tcp4_listen1, NULL }; #endif #endif /* WITH_IP4 */ #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("::") }; +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("::") }; +const union xioaddr_desc *xioaddrs_tcp6_connect[] = {(union xioaddr_desc *) &xioendpoint_tcp6_connect2, NULL }; #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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_tcp6_listen[] = { (union xioaddr_desc *)&xioendpoint_tcp6_listen1, NULL }; #endif #endif /* WITH_IP6 */ @@ -83,10 +89,10 @@ const struct optdesc opt_tcp_info = { "tcp-info", "info", OPT_TCP_INFO, const struct optdesc opt_tcp_quickack = { "tcp-quickack", "quickack", OPT_TCP_QUICKACK, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_QUICKACK }; #endif #ifdef TCP_NOOPT -const struct optdesc opt_tcp_noopt = { "tcp-noopt", "noopt", OPT_TCP_NOOPT, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_NOOPT }; +const struct optdesc opt_tcp_noopt = { "tcp-noopt", "noopt", OPT_TCP_NOOPT, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_NOOPT }; #endif #ifdef TCP_NOPUSH -const struct optdesc opt_tcp_nopush = { "tcp-nopush", "nopush", OPT_TCP_NOPUSH, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_NOPUSH }; +const struct optdesc opt_tcp_nopush = { "tcp-nopush", "nopush", OPT_TCP_NOPUSH, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_NOPUSH }; #endif #ifdef TCP_MD5SIG const struct optdesc opt_tcp_md5sig = { "tcp-md5sig", "md5sig", OPT_TCP_MD5SIG, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_MD5SIG }; diff --git a/xio-tcp.h b/xio-tcp.h index 041c601..927fbaf 100644 --- a/xio-tcp.h +++ b/xio-tcp.h @@ -1,16 +1,16 @@ -/* $Id: xio-tcp.h,v 1.12 2006/03/21 20:59:34 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001-2006 */ +/* $Id: xio-tcp.h,v 1.12.2.1 2006/07/24 19:18:42 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_tcp_h_included #define __xio_tcp_h_included 1 -extern const struct addrdesc addr_tcp_connect; -extern const struct addrdesc addr_tcp_listen; -extern const struct addrdesc addr_tcp4_connect; -extern const struct addrdesc addr_tcp4_listen; -extern const struct addrdesc addr_tcp6_connect; -extern const struct addrdesc addr_tcp6_listen; +extern const union xioaddr_desc *xioaddrs_tcp_connect[]; +extern const union xioaddr_desc *xioaddrs_tcp_listen[]; +extern const union xioaddr_desc *xioaddrs_tcp4_connect[]; +extern const union xioaddr_desc *xioaddrs_tcp4_listen[]; +extern const union xioaddr_desc *xioaddrs_tcp6_connect[]; +extern const union xioaddr_desc *xioaddrs_tcp6_listen[]; extern const struct optdesc opt_tcp_nodelay; extern const struct optdesc opt_tcp_maxseg; diff --git a/xio-tcpwrap.c b/xio-tcpwrap.c index 4ab19c2..cb05757 100644 --- a/xio-tcpwrap.c +++ b/xio-tcpwrap.c @@ -131,11 +131,11 @@ int xio_tcpwrap_check(xiosingle_t *xfd, union sockaddr_union *us, 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", - &ri, xfd->fd, clientaddr, + &ri, xfd->fd1, clientaddr, ntohs(((struct sockaddr_in *)them)->sin_port), serveraddr, ntohs(us->ip4.sin_port), 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_SERVER_SIN, &us->soa, RQ_DAEMON, xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p'), 0); diff --git a/xio-test.c b/xio-test.c new file mode 100644 index 0000000..52c46e4 --- /dev/null +++ b/xio-test.c @@ -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 */ + diff --git a/xio-test.h b/xio-test.h new file mode 100644 index 0000000..dd70f0a --- /dev/null +++ b/xio-test.h @@ -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) */ diff --git a/xio-tun.c b/xio-tun.c index 2ed0f87..1091443 100644 --- a/xio-tun.c +++ b/xio-tun.c @@ -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 }; #endif -const struct addrdesc xioaddr_tun = { "tun", 3, xioopen_tun, GROUP_FD|GROUP_CHR|GROUP_NAMED|GROUP_OPEN|GROUP_TUN, 0, 0, 0 HELP(":/") }; +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(":/") }; + +const union xioaddr_desc *xioaddrs_tun[] = { + (union xioaddr_desc *)&xioendpoint_tun1, + NULL +}; + // "if-name"=tun3 // "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"); if ((result = _xioopen_open(tundevice, rw, opts)) < 0) return result; - xfd->stream.fd = result; + xfd->stream.fd1 = result; /* prepare configuration of the new network interface */ 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", - xfd->stream.fd, ifr.ifr_name, strerror(errno)); - Close(xfd->stream.fd); + xfd->stream.fd1, ifr.ifr_name, strerror(errno)); + Close(xfd->stream.fd1); } /*===================== 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 */ if ((sockfd = Socket(PF_INET, SOCK_DGRAM, 0)) < 0) { 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 ------------*/ @@ -195,10 +201,10 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl #if LATER applyopts_named(tundevice, opts, PH_FD); #endif - applyopts(xfd->stream.fd, opts, PH_FD); - applyopts_cloexec(xfd->stream.fd, opts); + applyopts(xfd->stream.fd1, opts, PH_FD); + 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) return result; diff --git a/xio-tun.h b/xio-tun.h index 53eb6c8..2c25e6a 100644 --- a/xio-tun.h +++ b/xio-tun.h @@ -28,6 +28,6 @@ extern const struct optdesc opt_iff_portsel; extern const struct optdesc opt_iff_automedia; /*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) */ diff --git a/xio-udp.c b/xio-udp.c index 4a23b3d..4a744bf 100644 --- a/xio-udp.c +++ b/xio-udp.c @@ -35,42 +35,59 @@ static int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int pf, int socktype, int ipproto); - static int _xioopen_udp_sendto(const char *hostname, const char *servname, struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, 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("::") }; +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("::") }; +const union xioaddr_desc *xioaddrs_udp_connect[] = { (union xioaddr_desc *)&xioaddr_udp_connect2, NULL }; #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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_udp_listen[] = { (union xioaddr_desc *)&xioaddr_udp_listen1, NULL }; #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("::") }; -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(":") }; -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(":") }; -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("::") }; +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("::") }; +const union xioaddr_desc *xioaddrs_udp_sendto[] = { (union xioaddr_desc *)&xioaddr_udp_sendto2, NULL }; +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(":") }; +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(":") }; +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("::") }; +const union xioaddr_desc *xioaddrs_udp_datagram[] = { (union xioaddr_desc *)&xioaddr_udp_datagram2, NULL }; #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("::") }; +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("::") }; +const union xioaddr_desc *xioaddrs_udp4_connect[] = { (union xioaddr_desc *)&xioaddr_udp4_connect2, NULL }; #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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_udp4_listen[] = { (union xioaddr_desc *)&xioaddr_udp4_listen1, NULL }; #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("::") }; -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("::") }; -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("::") }; -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(":") }; +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("::") }; +const union xioaddr_desc *xioaddrs_udp4_sendto[] = { (union xioaddr_desc *)&xioaddr_udp4_sendto2, NULL }; +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("::") }; +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("::") }; +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(":") }; +const union xioaddr_desc *xioaddrs_udp4_recv[] = { (union xioaddr_desc *)&xioaddr_udp4_recv1, NULL }; #endif /* WITH_IP4 */ #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("::") }; +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("::") }; +const union xioaddr_desc *xioaddrs_udp6_connect[] = { (union xioaddr_desc *)&xioaddr_udp6_connect2, NULL }; #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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_udp6_listen[] = { (union xioaddr_desc *)&xioaddr_udp6_listen1, NULL }; #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("::") }; -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("::") }; -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(":") }; -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(":") }; +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("::") }; +const union xioaddr_desc *xioaddrs_udp6_sendto[] = { (union xioaddr_desc *)&xioaddr_udp6_sendto2, NULL }; +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("::") }; +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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_udp6_recv[] = { (union xioaddr_desc *)&xioaddr_udp6_recv1, NULL }; #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; applyopts(-1, opts, PH_INIT); + fd->stream.fdtype = FDTYPE_SINGLE; + uslen = socket_init(pf, &us); retropt_int(opts, OPT_SO_TYPE, &socktype); 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 *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)); return STAT_RETRYLATER; } - applyopts(fd->stream.fd, opts, PH_PASTSOCKET); - if (Setsockopt(fd->stream.fd, opt_so_reuseaddr.major, + /*0 Info4("socket(%d, %d, %d) -> %d", pf, socktype, ipproto, fd->stream.fd);*/ + applyopts(fd->stream.fd1, opts, PH_PASTSOCKET); + if (Setsockopt(fd->stream.fd1, opt_so_reuseaddr.major, opt_so_reuseaddr.minor, &one, sizeof(one)) < 0) { 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)); } - applyopts_cloexec(fd->stream.fd, opts); - applyopts(fd->stream.fd, opts, PH_PREBIND); - applyopts(fd->stream.fd, opts, PH_BIND); - if (Bind(fd->stream.fd, &us.soa, uslen) < 0) { - Error4("bind(%d, {%s}, "F_Zd"): %s", fd->stream.fd, + applyopts_cloexec(fd->stream.fd1, opts); + applyopts(fd->stream.fd1, opts, PH_PREBIND); + applyopts(fd->stream.fd1, opts, PH_BIND); + if (Bind(fd->stream.fd1, &us.soa, uslen) < 0) { + Error4("bind(%d, {%s}, "F_Zd"): %s", fd->stream.fd1, sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)), uslen, strerror(errno)); return STAT_RETRYLATER; } /* 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", - 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", sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff))); FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt); - FD_SET(fd->stream.fd, &in); - while (Select(fd->stream.fd+1, &in, &out, &expt, NULL) < 0) { + FD_SET(fd->stream.fd1, &in); + while (Select(fd->stream.fd1+1, &in, &out, &expt, NULL) < 0) { if (errno != EINTR) break; } themlen = socket_init(pf, them); do { - result = Recvfrom(fd->stream.fd, buff1, 1, MSG_PEEK, + result = Recvfrom(fd->stream.fd1, buff1, 1, MSG_PEEK, &them->soa, &themlen); } while (result < 0 && errno == EINTR); if (result < 0) { 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)), themlen, strerror(errno)); return STAT_RETRYLATER; } - Notice1("accepting UDP connection from %s", sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff))); if (xiocheckpeer(&fd->stream, them, la) < 0) { /* drop packet */ char buff[512]; - Recv(fd->stream.fd, buff, sizeof(buff), 0); + Recv(fd->stream.fd1, buff, sizeof(buff), 0); continue; } 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 */ /* when we dont close this we get awkward behaviour on Linux 2.4: recvfrom gives 0 bytes with invalid socket address */ - if (Close(fd->stream.fd) < 0) { - Info2("close(%d): %s", fd->stream.fd, strerror(errno)); + if (Close(fd->stream.fd1) < 0) { + Info2("close(%d): %s", fd->stream.fd1, strerror(errno)); } Notice1("forked off child process "F_pid, pid); 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; } - applyopts(fd->stream.fd, opts, PH_CONNECT); - if ((result = Connect(fd->stream.fd, &them->soa, themlen)) < 0) { + applyopts(fd->stream.fd1, opts, PH_CONNECT); + if ((result = Connect(fd->stream.fd1, &them->soa, themlen)) < 0) { Error4("connect(%d, {%s}, "F_Zd"): %s", - fd->stream.fd, + fd->stream.fd1, sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)), themlen, strerror(errno)); return STAT_RETRYLATER; } - fd->stream.howtoend = END_SHUTDOWN; - applyopts_fchown(fd->stream.fd, opts); - applyopts(fd->stream.fd, opts, PH_LATE); + applyopts_fchown(fd->stream.fd1, opts); + applyopts(fd->stream.fd1, opts, PH_LATE); if ((result = _xio_openlate(&fd->stream, opts)) < 0) return result; @@ -312,7 +330,6 @@ int _xioopen_udp_sendto(const char *hostname, const char *servname, bool needbind = false; int result; - xfd->howtoend = END_SHUTDOWN; retropt_int(opts, OPT_SO_TYPE, &socktype); /* ...res_opts[] */ @@ -452,7 +469,6 @@ int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts, return STAT_NORETRY; } - xfd->stream.howtoend = END_NONE; retropt_socket_pf(opts, &pf); if (pf == PF_UNSPEC) { #if WITH_IP4 && WITH_IP6 diff --git a/xio-udp.h b/xio-udp.h index 3ccf0dd..860636c 100644 --- a/xio-udp.h +++ b/xio-udp.h @@ -5,24 +5,24 @@ #ifndef __xio_udp_h_included #define __xio_udp_h_included 1 -extern const struct addrdesc addr_udp_connect; -extern const struct addrdesc addr_udp_listen; -extern const struct addrdesc addr_udp_sendto; -extern const struct addrdesc addr_udp_datagram; -extern const struct addrdesc addr_udp_recvfrom; -extern const struct addrdesc addr_udp_recv; -extern const struct addrdesc addr_udp4_connect; -extern const struct addrdesc addr_udp4_listen; -extern const struct addrdesc addr_udp4_sendto; -extern const struct addrdesc addr_udp4_datagram; -extern const struct addrdesc addr_udp4_recvfrom; -extern const struct addrdesc addr_udp4_recv; -extern const struct addrdesc addr_udp6_connect; -extern const struct addrdesc addr_udp6_listen; -extern const struct addrdesc addr_udp6_sendto; -extern const struct addrdesc addr_udp6_datagram; -extern const struct addrdesc addr_udp6_recvfrom; -extern const struct addrdesc addr_udp6_recv; +extern const union xioaddr_desc *xioaddrs_udp_connect[]; +extern const union xioaddr_desc *xioaddrs_udp_listen[]; +extern const union xioaddr_desc *xioaddrs_udp_sendto[]; +extern const union xioaddr_desc *xioaddrs_udp_datagram[]; +extern const union xioaddr_desc *xioaddrs_udp_recvfrom[]; +extern const union xioaddr_desc *xioaddrs_udp_recv[]; +extern const union xioaddr_desc *xioaddrs_udp4_connect[]; +extern const union xioaddr_desc *xioaddrs_udp4_listen[]; +extern const union xioaddr_desc *xioaddrs_udp4_sendto[]; +extern const union xioaddr_desc *xioaddrs_udp4_datagram[]; +extern const union xioaddr_desc *xioaddrs_udp4_recvfrom[]; +extern const union xioaddr_desc *xioaddrs_udp4_recv[]; +extern const union xioaddr_desc *xioaddrs_udp6_connect[]; +extern const union xioaddr_desc *xioaddrs_udp6_listen[]; +extern const union xioaddr_desc *xioaddrs_udp6_sendto[]; +extern const union xioaddr_desc *xioaddrs_udp6_datagram[]; +extern const union xioaddr_desc *xioaddrs_udp6_recvfrom[]; +extern const union xioaddr_desc *xioaddrs_udp6_recv[]; extern int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, int rw, xiofile_t *fd, diff --git a/xio-unix.c b/xio-unix.c index c0d9ecb..508918b 100644 --- a/xio-unix.c +++ b/xio-unix.c @@ -25,7 +25,6 @@ int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts, int pf, int socktype, int ipproto); 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); - #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_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); #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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_unix_connect[] = { (union xioaddr_desc *)&xioendpoint_unix_connect1, NULL }; #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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_unix_listen[] = { (union xioaddr_desc *)&xioendpoint_unix_listen1, NULL }; #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(":") }; -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(":") }; -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(":") }; -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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_unix_sendto[] = { (union xioaddr_desc *)&xioendpoint_unix_sendto1, NULL }; +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(":") }; +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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_unix_client[] = { (union xioaddr_desc *)&xioendpoint_unix_client1, NULL }; + #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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_abstract_connect[] = { (union xioaddr_desc *)&xioendpoint_abstract_connect1, NULL }; #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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_abstract_listen[] = { (union xioaddr_desc *)&xioendpoint_abstract_listen1, NULL }; #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(":") }; -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(":") }; -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(":") }; -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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_abstract_sendto[] = { (union xioaddr_desc *)&xioendpoint_abstract_sendto1, NULL }; +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(":") }; +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(":") }; +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(":") }; +const union xioaddr_desc *xioaddrs_abstract_client[] = { (union xioaddr_desc *)&xioendpoint_abstract_client1, NULL }; #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 }; @@ -133,8 +145,6 @@ static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, i xfd->opt_unlink_close = true; } - xfd->howtoend = END_SHUTDOWN; - applyopts(-1, opts, PH_INIT); if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; 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); xfd->salen = socket_init(pf, &xfd->peersa); - xfd->howtoend = END_SHUTDOWN; - retropt_int(opts, OPT_SO_TYPE, &socktype); 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]; uslen = xiosetunix(&us, name, false, tight); - xfd->stream.howtoend = END_NONE; retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0); 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); } - xfd->howtoend = END_SHUTDOWN; retropt_int(opts, OPT_SO_TYPE, &socktype); 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]; uslen = xiosetunix(&us, name, true, tight); - xfd->howtoend = END_SHUTDOWN; - applyopts(-1, opts, PH_INIT); if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; 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); xfd->salen = socket_init(pf, &xfd->peersa); - xfd->howtoend = END_SHUTDOWN; - retropt_int(opts, OPT_SO_TYPE, &socktype); 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]; uslen = xiosetunix(&us, name, true, tight); - xfd->stream.howtoend = END_NONE; retropt_int(opts, OPT_SO_TYPE, &socktype); 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); } - xfd->howtoend = END_SHUTDOWN; retropt_int(opts, OPT_SO_TYPE, &socktype); uslen = socket_init(pf, &us); diff --git a/xio-unix.h b/xio-unix.h index 3cea77e..99fe1d7 100644 --- a/xio-unix.h +++ b/xio-unix.h @@ -5,18 +5,18 @@ #ifndef __xio_unix_h_included #define __xio_unix_h_included 1 -extern const struct addrdesc addr_unix_connect; -extern const struct addrdesc addr_unix_listen; -extern const struct addrdesc addr_unix_sendto; -extern const struct addrdesc addr_unix_recvfrom; -extern const struct addrdesc addr_unix_recv; -extern const struct addrdesc addr_unix_client; -extern const struct addrdesc xioaddr_abstract_connect; -extern const struct addrdesc xioaddr_abstract_listen; -extern const struct addrdesc xioaddr_abstract_sendto; -extern const struct addrdesc xioaddr_abstract_recvfrom; -extern const struct addrdesc xioaddr_abstract_recv; -extern const struct addrdesc xioaddr_abstract_client; +extern const union xioaddr_desc *xioaddrs_unix_connect[]; +extern const union xioaddr_desc *xioaddrs_unix_listen[]; +extern const union xioaddr_desc *xioaddrs_unix_sendto[]; +extern const union xioaddr_desc *xioaddrs_unix_recvfrom[]; +extern const union xioaddr_desc *xioaddrs_unix_recv[]; +extern const union xioaddr_desc *xioaddrs_unix_client[]; +extern const union xioaddr_desc *xioaddrs_abstract_connect[]; +extern const union xioaddr_desc *xioaddrs_abstract_listen[]; +extern const union xioaddr_desc *xioaddrs_abstract_sendto[]; +extern const union xioaddr_desc *xioaddrs_abstract_recvfrom[]; +extern const union xioaddr_desc *xioaddrs_abstract_recv[]; +extern const union xioaddr_desc *xioaddrs_abstract_client[]; extern const struct optdesc opt_unix_tightsocklen; diff --git a/xio.h b/xio.h index 649f854..5bf5ad6 100644 --- a/xio.h +++ b/xio.h @@ -19,7 +19,7 @@ #define LINETERM_CR 1 #define LINETERM_CRNL 2 -struct addrdesc; +union xioaddr_desc; struct opt; /* the flags argument of xioopen */ @@ -27,18 +27,37 @@ struct opt; #define XIO_WRONLY O_WRONLY /* asserted to be 1 */ #define XIO_RDWR O_RDWR /* asserted to be 2 */ #define XIO_ACCMODE O_ACCMODE /* must be 3 */ -#define XIO_MAYFORK 4 /* address is allowed to fork the program (fork) */ -#define XIO_MAYCHILD 8 /* address is allowed to fork off a child (exec)*/ +/* 3 is undefined */ +#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_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 */ #define XIO_DOESFORK XIO_MAYFORK #define XIO_DOESCHILD XIO_MAYCHILD #define XIO_DOESEXEC XIO_MAYEXEC #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<common.flags+1)&2) #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_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_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_GETRDFD(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]->fd1:(s)->stream.fd1) +#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) typedef unsigned long flags_t; @@ -357,6 +556,12 @@ struct opt { 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 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; not even by external changes correctable */ -extern int xioinitialize(void); +extern int xioinitialize(int xioflags); extern int xio_forked_inchild(void); extern int xiosetopt(char what, const char *arg); extern int xioinqopt(char what, char *arg, size_t n); -extern xiofile_t *xioopen(const char *args, int flags); -extern int xioopensingle(char *addr, struct single *xfd, int xioflags); +extern xiofile_t *xioopen(const char *args, 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); /* must be outside function for use by childdied handler */ -extern xiofile_t *sock1, *sock2; -extern pid_t diedunknown1; /* child died before it is registered */ -extern pid_t diedunknown2; -extern pid_t diedunknown3; -extern pid_t diedunknown4; +extern xiofile_t *xioallocfd(void); +extern void xiofreefd(xiofile_t *xfd); -extern int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)); 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 xiopending(xiofile_t *sock1); 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 xioclose(xiofile_t *sock); extern void xioexit(void); 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) */ diff --git a/xioclose.c b/xioclose.c index 026e55c..17b802a 100644 --- a/xioclose.c +++ b/xioclose.c @@ -21,62 +21,81 @@ int xioclose1(struct single *pipe) { return -1; } + switch (pipe->howtoclose) { + #if WITH_READLINE - if ((pipe->dtype & XIODATA_MASK) == XIODATA_READLINE) { + case XIOCLOSE_READLINE: Write_history(pipe->para.readline.history_file); /*xiotermios_setflag(pipe->fd, 3, ECHO|ICANON);*/ /* error when pty closed */ - } + break; #endif /* WITH_READLINE */ + #if WITH_OPENSSL - if ((pipe->dtype & XIODATA_MASK) == XIODATA_OPENSSL) { + case XIOCLOSE_OPENSSL: if (pipe->para.openssl.ssl) { /* e.g. on TCP connection refused, we do not yet have this set */ sycSSL_shutdown(pipe->para.openssl.ssl); sycSSL_free(pipe->para.openssl.ssl); 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) { sycSSL_CTX_free(pipe->para.openssl.ctx); pipe->para.openssl.ctx = NULL; } - } else + break; #endif /* WITH_OPENSSL */ + #if WITH_TERMIOS 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", - pipe->fd, strerror(errno)); + pipe->fd1, strerror(errno)); } } #endif /* WITH_TERMIOS */ - if (pipe->fd >= 0) { - switch (pipe->howtoend) { - case END_KILL: case END_SHUTDOWN_KILL: case END_CLOSE_KILL: - if (pipe->para.exec.pid > 0) { - if (Kill(pipe->para.exec.pid, SIGTERM) < 0) { - Msg2(errno==ESRCH?E_INFO:E_WARN, "kill(%d, SIGTERM): %s", - pipe->para.exec.pid, strerror(errno)); - } + + case XIOCLOSE_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)); } - default: - 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; + 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: + Error2("xioclose(): bad end action 0x%x on 0x%x", pipe->howtoclose, pipe); + break; } /* unlock */ @@ -98,6 +117,7 @@ int xioclose1(struct single *pipe) { /* close the xio fd */ int xioclose(xiofile_t *file) { + xiofile_t *xfd = file; int result; if (file->tag == XIO_TAG_INVALID) { @@ -113,6 +133,9 @@ int xioclose(xiofile_t *file) { } else { result = xioclose1(&file->stream); } + if (xfd->stream.subthread != 0) { + Pthread_join(xfd->stream.subthread, NULL); + } return result; } diff --git a/xioconfig.h b/xioconfig.h index 4da8c5d..114e972 100644 --- a/xioconfig.h +++ b/xioconfig.h @@ -21,23 +21,26 @@ #endif #if WITH_SOCKS4A -# define WITH_SOCKS4 1 +# define _WITH_SOCKS4 1 #endif -#if WITH_SOCKS4 || WITH_PROXY -# define WITH_TCP 1 -# define WITH_IP4 1 /* currently this socks implementation does not work +#if WITH_SOCKS4 || WITH_SOCKS5 || WITH_PROXY +# define _WITH_TCP 1 +# define _WITH_IP4 1 /* currently this socks implementation does not work with IP6 */ #endif -#if WITH_OPENSSL -# define WITH_TCP 1 -# define WITH_IP4 1 +#if 0 +#if !defined(HAVE_NETINET_IP6_H) +# undef WITH_IP6 +#endif #endif -#if WITH_IP6 -# if !defined(HAVE_NETINET_IP6_H) -# undef WITH_IP6 +#if WITH_OPENSSL +# define _WITH_TCP 1 +# define _WITH_IP4 1 +# if WITH_IP6 +# define _WITH_IP6 1 # endif #endif @@ -47,7 +50,11 @@ # 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 #else # undef WITH_SOCKET @@ -65,6 +72,14 @@ # define _WITH_SOCKET 1 #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 # define _WITH_IP4 1 #endif diff --git a/xioengine.c b/xioengine.c new file mode 100644 index 0000000..92728aa --- /dev/null +++ b/xioengine.c @@ -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; +} diff --git a/xiohelp.c b/xiohelp.c index 508e596..5540e53 100644 --- a/xiohelp.c +++ b/xiohelp.c @@ -41,7 +41,7 @@ static const char *addressgroupnames[] = { "TERMIOS", "RANGE", "PTY", "PARENT", "UNIX", "IP4", "IP6", "INTERFACE", "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 level /* 0..only addresses, 1..and options */ ) { - const struct addrname *an; + const struct xioaddrname *an; const struct optname *on; int i, j; unsigned int groups; @@ -101,32 +101,68 @@ int xioopenhelp(FILE *of, fputs(" echo is an alias for pipe\n", of); fputs(" fifo is an alias for pipe\n", of); } - fputs(" !!\n", of); + fputs(" %\n", of); fputs(" \n", of); fputs(" single-address:\n", of); fputs(" [,]\n", of); fputs(" address-head:\n", of); - an = &addressnames[0]; + an = &address_names[0]; i = 0; - while (addressnames[i].name) { - if (!strcmp(an->name, an->desc->defname)) { + while (address_names[i].name) { + if (!strcmp(an->name, (an->desc)[0]->common_desc.defname)) { /* it is a canonical address name */ - fprintf(of, " %s", an->name); - if (an->desc->syntax) { - fputs(an->desc->syntax, of); } - fputs("\tgroups=", of); - groups = an->desc->groups; occurred = false; + const union xioaddr_desc **ad; + ad = an->desc; + while (*ad != NULL) { + const char *syntax; + 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) { if (groups & 1) { if (occurred) { fputc(',', of); } fprintf(of, "%s", addressgroupnames[j]); + pos += strlen(addressgroupnames[j]); occurred = true; } groups >>= 1; } fputc('\n', of); + ++ad; + } } 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; } diff --git a/xioinitialize.c b/xioinitialize.c index 84e4e3c..e9b6fcd 100644 --- a/xioinitialize.c +++ b/xioinitialize.c @@ -1,24 +1,30 @@ /* $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 */ /* this file contains the source for the initialize function */ #include "xiosysincludes.h" +#include "xiostatic.h" #include "xioopen.h" #include "xiolockfile.h" +#include "xiosigchld.h" #include "xio-openssl.h" /* xio_reset_fips_mode() */ static int xioinitialized; 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 */ +/* 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 */ -int xioinitialize(void) { +int xioinitialize(int xioflags) { + int xio_flags; if (xioinitialized) return 0; /* configure and .h's cannot guarantee this */ @@ -67,7 +73,7 @@ int xioinitialize(void) { assert(tdata.termarg.c_ospeed == tdata.speeds[OSPEED_OFFSET]); #endif } -#endif +#endif /* WITH_TERMIOS */ /* these dependencies required in applyopts() for OFUNC_FCNTL */ assert(F_GETFD == F_SETFD-1); @@ -103,15 +109,41 @@ int xioinitialize(void) { 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; return 0; } /* 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 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) { int i; @@ -124,6 +156,7 @@ void xiodroplocks(void) { } +#if 0 /* consider an invokation like this: 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 @@ -146,16 +179,17 @@ static int xio_nokill(xiofile_t *sock) { case XIO_TAG_WRONLY: case XIO_TAG_RDWR: /* here is the core of this function */ - switch (sock->stream.howtoend) { - case END_SHUTDOWN_KILL: sock->stream.howtoend = END_CLOSE; break; - case END_CLOSE_KILL: sock->stream.howtoend = END_CLOSE; break; - case END_SHUTDOWN: sock->stream.howtoend = END_CLOSE; break; + switch (sock->stream.howtoclose) { + case END_SHUTDOWN_KILL: sock->stream.howtoclose = END_CLOSE; break; + case END_CLOSE_KILL: sock->stream.howtoclose = END_CLOSE; break; + case END_SHUTDOWN: sock->stream.howtoclose = END_CLOSE; break; default: break; } break; } return result; } +#endif /* 0 */ /* call this function immediately after fork() in child process */ /* it performs some neccessary actions @@ -175,6 +209,7 @@ int xio_forked_inchild(void) { } } +#if 0 /* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */ if (sock1 != NULL) { int result2; @@ -182,6 +217,7 @@ int xio_forked_inchild(void) { if (result2 < 0) Exit(1); result |= result2; } +#endif return result; } diff --git a/xiolayer.c b/xiolayer.c index 2e0bc18..4183db1 100644 --- a/xiolayer.c +++ b/xiolayer.c @@ -1,5 +1,5 @@ /* $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 */ /* 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 }; /****** APPL addresses ******/ #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_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_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_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_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_OFFSET, (int)(&((struct single *)0)->retry), sizeof(((struct single *)0)->retry) }; #endif diff --git a/xiomodes.h b/xiomodes.h index afeae15..f2e625b 100644 --- a/xiomodes.h +++ b/xiomodes.h @@ -29,6 +29,7 @@ #include "xio-tcp.h" #include "xio-udp.h" #include "xio-socks.h" +#include "xio-socks5.h" #include "xio-proxy.h" #endif /* WITH_SOCKET */ #include "xio-progcall.h" @@ -41,5 +42,7 @@ #include "xio-tcpwrap.h" #include "xio-ext2.h" #include "xio-tun.h" +#include "xio-nop.h" +#include "xio-test.h" #endif /* !defined(__xiomodes_h_included) */ diff --git a/xioopen.c b/xioopen.c index 59d8e7f..6180510 100644 --- a/xioopen.c +++ b/xioopen.c @@ -10,240 +10,274 @@ #include "xiomodes.h" #include "nestlex.h" -static xiofile_t *xioallocfd(void); +#include "xiosigchld.h" -xiosingle_t hugo; +void *xioopenleftthenengine(void *thread_void); static xiosingle_t *xioparse_single(const char **addr); -static xiofile_t *xioparse_dual(const char **addr); -static int xioopen_dual(xiofile_t *xfd, int xioflags); -const struct addrname addressnames[] = { +static int + xioopen_inter_single(xiofile_t *xfd, int xioflags); +static int + xioopen_endpoint_single(xiofile_t *xfd, int xioflags); +static int + xioopen_unoverload(xiosingle_t *sfd, + int mayleft, /* what may be on left side: or'd + XIOBIT_RDWR, XIOBIT_RDONLY, + XIOBIT_WRONLY */ + int *isleft, /* what the selected address desc + provides on left side: XIO_RDWR, + XIO_RDONLY, or XIO_WRONLY */ + int mayright, /* what may be on right side: or'd + XIOBIT_RDWR, XIOBIT_RDONLY, + XIOBIT_WRONLY */ + int *isright); /* what the selected address desc + provides on right side: XIO_RDWR, + XIO_RDONLY, or XIO_WRONLY */ + + +const struct xioaddrname address_names[] = { #if 1 #if WITH_STDIO - { "-", &addr_stdio }, + { "-", xioaddrs_stdio }, #endif #if defined(WITH_UNIX) && defined(WITH_ABSTRACT_UNIXSOCKET) - { "abstract", &xioaddr_abstract_client }, - { "abstract-client", &xioaddr_abstract_client }, - { "abstract-connect", &xioaddr_abstract_connect }, + { "abstract", xioaddrs_abstract_client }, + { "abstract-client", xioaddrs_abstract_client }, + { "abstract-connect", xioaddrs_abstract_connect }, #if WITH_LISTEN - { "abstract-listen", &xioaddr_abstract_listen }, + { "abstract-listen", xioaddrs_abstract_listen }, #endif - { "abstract-recv", &xioaddr_abstract_recv }, - { "abstract-recvfrom", &xioaddr_abstract_recvfrom }, - { "abstract-sendto", &xioaddr_abstract_sendto }, + { "abstract-recv", xioaddrs_abstract_recv }, + { "abstract-recvfrom", xioaddrs_abstract_recvfrom }, + { "abstract-sendto", xioaddrs_abstract_sendto }, #endif /* defined(WITH_UNIX) && defined(WITH_ABSTRACT_UNIXSOCKET) */ #if WITH_CREAT - { "creat", &addr_creat }, - { "create", &addr_creat }, + { "creat", xioaddrs_creat }, + { "create", xioaddrs_creat }, #endif #if WITH_PIPE - { "echo", &addr_pipe }, + { "echo", xioaddrs_pipe }, #endif #if WITH_EXEC - { "exec", &addr_exec }, + { "exec", xioaddrs_exec }, #endif #if WITH_FDNUM - { "fd", &addr_fd }, + { "fd", xioaddrs_fdnum }, #endif #if WITH_PIPE - { "fifo", &addr_pipe }, + { "fifo", xioaddrs_pipe }, #endif #if WITH_FILE - { "file", &addr_open }, + { "file", xioaddrs_open }, #endif #if WITH_GOPEN - { "gopen", &addr_gopen }, + { "gopen", xioaddrs_gopen }, #endif #if (WITH_IP4 || WITH_IP6) && WITH_TCP - { "inet", &addr_tcp_connect }, + { "inet", xioaddrs_tcp_connect }, #endif #if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN - { "inet-l", &addr_tcp_listen }, - { "inet-listen", &addr_tcp_listen }, + { "inet-l", xioaddrs_tcp_listen }, + { "inet-listen", xioaddrs_tcp_listen }, #endif #if WITH_IP4 && WITH_TCP - { "inet4", &addr_tcp4_connect }, + { "inet4", xioaddrs_tcp4_connect }, #endif #if WITH_IP4 && WITH_TCP && WITH_LISTEN - { "inet4-l", &addr_tcp4_listen }, - { "inet4-listen", &addr_tcp4_listen }, + { "inet4-l", xioaddrs_tcp4_listen }, + { "inet4-listen", xioaddrs_tcp4_listen }, #endif #if WITH_IP6 && WITH_TCP - { "inet6", &addr_tcp6_connect }, + { "inet6", xioaddrs_tcp6_connect }, #endif #if WITH_IP6 && WITH_TCP && WITH_LISTEN - { "inet6-l", &addr_tcp6_listen }, - { "inet6-listen", &addr_tcp6_listen }, + { "inet6-l", xioaddrs_tcp6_listen }, + { "inet6-listen", xioaddrs_tcp6_listen }, #endif #if WITH_RAWIP #if (WITH_IP4 || WITH_IP6) - { "ip", &addr_rawip_sendto }, - { "ip-datagram", &addr_rawip_datagram }, - { "ip-dgram", &addr_rawip_datagram }, - { "ip-recv", &addr_rawip_recv }, - { "ip-recvfrom", &addr_rawip_recvfrom }, - { "ip-send", &addr_rawip_sendto }, - { "ip-sendto", &addr_rawip_sendto }, + { "ip", xioaddrs_rawip_sendto }, + { "ip-datagram", xioaddrs_rawip_datagram }, + { "ip-dgram", xioaddrs_rawip_datagram }, + { "ip-recv", xioaddrs_rawip_recv }, + { "ip-recvfrom", xioaddrs_rawip_recvfrom }, + { "ip-send", xioaddrs_rawip_sendto }, + { "ip-sendto", xioaddrs_rawip_sendto }, #endif #if WITH_IP4 - { "ip4", &addr_rawip4_sendto }, - { "ip4-datagram", &addr_rawip4_datagram }, - { "ip4-dgram", &addr_rawip4_datagram }, - { "ip4-recv", &addr_rawip4_recv }, - { "ip4-recvfrom", &addr_rawip4_recvfrom }, - { "ip4-send", &addr_rawip4_sendto }, - { "ip4-sendto", &addr_rawip4_sendto }, + { "ip4", xioaddrs_rawip4_sendto }, + { "ip4-datagram", xioaddrs_rawip4_datagram }, + { "ip4-dgram", xioaddrs_rawip4_datagram }, + { "ip4-recv", xioaddrs_rawip4_recv }, + { "ip4-recvfrom", xioaddrs_rawip4_recvfrom }, + { "ip4-send", xioaddrs_rawip4_sendto }, + { "ip4-sendto", xioaddrs_rawip4_sendto }, #endif #if WITH_IP6 - { "ip6", &addr_rawip6_sendto }, - { "ip6-datagram", &addr_rawip6_datagram }, - { "ip6-dgram", &addr_rawip6_datagram }, - { "ip6-recv", &addr_rawip6_recv }, - { "ip6-recvfrom", &addr_rawip6_recvfrom }, - { "ip6-send", &addr_rawip6_sendto }, - { "ip6-sendto", &addr_rawip6_sendto }, + { "ip6", xioaddrs_rawip6_sendto }, + { "ip6-datagram", xioaddrs_rawip6_datagram }, + { "ip6-dgram", xioaddrs_rawip6_datagram }, + { "ip6-recv", xioaddrs_rawip6_recv }, + { "ip6-recvfrom", xioaddrs_rawip6_recvfrom }, + { "ip6-send", xioaddrs_rawip6_sendto }, + { "ip6-sendto", xioaddrs_rawip6_sendto }, #endif #endif /* WITH_RAWIP */ #if WITH_UNIX - { "local", &addr_unix_connect }, + { "local", xioaddrs_unix_connect }, +#endif +#if WITH_NOP + { "nop", xioaddrs_nop }, #endif #if WITH_FILE - { "open", &addr_open }, + { "open", xioaddrs_open }, #endif #if WITH_OPENSSL - { "openssl", &addr_openssl }, - { "openssl-connect", &addr_openssl }, + { "openssl", xioaddrs_openssl_connect }, + { "openssl-client", xioaddrs_openssl_connect }, + { "openssl-connect", xioaddrs_openssl_connect }, #if WITH_LISTEN - { "openssl-listen", &addr_openssl_listen }, + { "openssl-listen", xioaddrs_openssl_listen }, + { "openssl-server", xioaddrs_openssl_listen }, #endif #endif #if WITH_PIPE - { "pipe", &addr_pipe }, + { "pipe", xioaddrs_pipe }, #endif #if WITH_PROXY - { "proxy", &addr_proxy_connect }, - { "proxy-connect", &addr_proxy_connect }, + { "proxy", xioaddrs_proxy_connect }, + { "proxy-connect", xioaddrs_proxy_connect }, #endif #if WITH_PTY - { "pty", &addr_pty }, + { "pty", xioaddrs_pty }, #endif #if WITH_READLINE - { "readline", &addr_readline }, + { "readline", xioaddrs_readline }, #endif #if WITH_SOCKS4 - { "socks", &addr_socks4_connect }, - { "socks4", &addr_socks4_connect }, + { "socks", xioaddrs_socks4_connect }, + { "socks-client", xioaddrs_socks4_connect }, + { "socks4", xioaddrs_socks4_connect }, + { "socks4-client", xioaddrs_socks4_connect }, #endif #if WITH_SOCKS4A - { "socks4a", &addr_socks4a_connect }, + { "socks4a", xioaddrs_socks4a_connect }, + { "socks4a-client", xioaddrs_socks4a_connect }, +#endif +#if WITH_SOCKS5 + { "socks5", xioaddrs_socks5_client }, + { "socks5-client", xioaddrs_socks5_client }, #endif #if WITH_OPENSSL - { "ssl", &addr_openssl }, + { "ssl", xioaddrs_openssl_connect }, #if WITH_LISTEN - { "ssl-l", &addr_openssl_listen }, + { "ssl-l", xioaddrs_openssl_listen }, + { "ssl-s", xioaddrs_openssl_listen }, #endif #endif #if WITH_STDIO - { "stderr", &addr_stderr }, - { "stdin", &addr_stdin }, - { "stdio", &addr_stdio }, - { "stdout", &addr_stdout }, + { "stderr", xioaddrs_stderr }, + { "stdin", xioaddrs_stdin }, + { "stdio", xioaddrs_stdio }, + { "stdout", xioaddrs_stdout }, #endif #if WITH_SYSTEM - { "system", &addr_system }, + { "system", xioaddrs_system }, #endif #if (WITH_IP4 || WITH_IP6) && WITH_TCP - { "tcp", &addr_tcp_connect }, - { "tcp-connect", &addr_tcp_connect }, + { "tcp", xioaddrs_tcp_connect }, + { "tcp-connect", xioaddrs_tcp_connect }, #endif #if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN - { "tcp-l", &addr_tcp_listen }, - { "tcp-listen", &addr_tcp_listen }, + { "tcp-l", xioaddrs_tcp_listen }, + { "tcp-listen", xioaddrs_tcp_listen }, #endif #if WITH_IP4 && WITH_TCP - { "tcp4", &addr_tcp4_connect }, - { "tcp4-connect", &addr_tcp4_connect }, + { "tcp4", xioaddrs_tcp4_connect }, + { "tcp4-connect", xioaddrs_tcp4_connect }, #endif #if WITH_IP4 && WITH_TCP && WITH_LISTEN - { "tcp4-l", &addr_tcp4_listen }, - { "tcp4-listen", &addr_tcp4_listen }, + { "tcp4-l", xioaddrs_tcp4_listen }, + { "tcp4-listen", xioaddrs_tcp4_listen }, #endif #if WITH_IP6 && WITH_TCP - { "tcp6", &addr_tcp6_connect }, - { "tcp6-connect", &addr_tcp6_connect }, + { "tcp6", xioaddrs_tcp6_connect }, + { "tcp6-connect", xioaddrs_tcp6_connect }, #endif #if WITH_IP6 && WITH_TCP && WITH_LISTEN - { "tcp6-l", &addr_tcp6_listen }, - { "tcp6-listen", &addr_tcp6_listen }, + { "tcp6-l", xioaddrs_tcp6_listen }, + { "tcp6-listen", xioaddrs_tcp6_listen }, +#endif +#if WITH_TEST + { "test", xioaddrs_test }, + { "testrev", xioaddrs_testrev }, + { "testuni", xioaddrs_testuni }, #endif #if WITH_TUN - { "tun", &xioaddr_tun }, + { "tun", xioaddrs_tun }, #endif #if (WITH_IP4 || WITH_IP6) && WITH_UDP - { "udp", &addr_udp_connect }, -#endif -#if (WITH_IP4 || WITH_IP6) && WITH_UDP - { "udp-connect", &addr_udp_connect }, - { "udp-datagram", &addr_udp_datagram }, - { "udp-dgram", &addr_udp_datagram }, + { "udp", xioaddrs_udp_connect }, + { "udp-connect", xioaddrs_udp_connect }, + { "udp-datagram", xioaddrs_udp_datagram }, + { "udp-dgram", xioaddrs_udp_datagram }, #endif #if (WITH_IP4 || WITH_IP6) && WITH_UDP && WITH_LISTEN - { "udp-l", &addr_udp_listen }, - { "udp-listen", &addr_udp_listen }, + { "udp-l", xioaddrs_udp_listen }, + { "udp-listen", xioaddrs_udp_listen }, #endif #if (WITH_IP4 || WITH_IP6) && WITH_UDP - { "udp-recv", &addr_udp_recv }, - { "udp-recvfrom", &addr_udp_recvfrom }, - { "udp-send", &addr_udp_sendto }, - { "udp-sendto", &addr_udp_sendto }, + { "udp-recv", xioaddrs_udp_recv }, + { "udp-recvfrom", xioaddrs_udp_recvfrom }, + { "udp-send", xioaddrs_udp_sendto }, + { "udp-sendto", xioaddrs_udp_sendto }, #endif #if WITH_IP4 && WITH_UDP - { "udp4", &addr_udp4_connect }, - { "udp4-connect", &addr_udp4_connect }, - { "udp4-datagram", &addr_udp4_datagram }, - { "udp4-dgram", &addr_udp4_datagram }, + { "udp4", xioaddrs_udp4_connect }, + { "udp4-connect", xioaddrs_udp4_connect }, + { "udp4-datagram", xioaddrs_udp4_datagram }, + { "udp4-dgram", xioaddrs_udp4_datagram }, #endif #if WITH_IP4 && WITH_UDP && WITH_LISTEN - { "udp4-l", &addr_udp4_listen }, - { "udp4-listen", &addr_udp4_listen }, + { "udp4-l", xioaddrs_udp4_listen }, + { "udp4-listen", xioaddrs_udp4_listen }, #endif #if WITH_IP4 && WITH_UDP - { "udp4-recv", &addr_udp4_recv }, - { "udp4-recvfrom", &addr_udp4_recvfrom }, - { "udp4-send", &addr_udp4_sendto }, - { "udp4-sendto", &addr_udp4_sendto }, + { "udp4-recv", xioaddrs_udp4_recv }, + { "udp4-recvfrom", xioaddrs_udp4_recvfrom }, + { "udp4-send", xioaddrs_udp4_sendto }, + { "udp4-sendto", xioaddrs_udp4_sendto }, #endif #if WITH_IP6 && WITH_UDP - { "udp6", &addr_udp6_connect }, - { "udp6-connect", &addr_udp6_connect }, - { "udp6-datagram", &addr_udp6_datagram }, - { "udp6-dgram", &addr_udp6_datagram }, + { "udp6", xioaddrs_udp6_connect }, + { "udp6-connect", xioaddrs_udp6_connect }, + { "udp6-datagram", xioaddrs_udp6_datagram }, + { "udp6-dgram", xioaddrs_udp6_datagram }, #endif #if WITH_IP6 && WITH_UDP && WITH_LISTEN - { "udp6-l", &addr_udp6_listen }, - { "udp6-listen", &addr_udp6_listen }, + { "udp6-l", xioaddrs_udp6_listen }, + { "udp6-listen", xioaddrs_udp6_listen }, #endif #if WITH_IP6 && WITH_UDP - { "udp6-recv", &addr_udp6_recv }, - { "udp6-recvfrom", &addr_udp6_recvfrom }, - { "udp6-send", &addr_udp6_sendto }, - { "udp6-sendto", &addr_udp6_sendto }, + { "udp6-recv", xioaddrs_udp6_recv }, + { "udp6-recvfrom", xioaddrs_udp6_recvfrom }, + { "udp6-send", xioaddrs_udp6_sendto }, + { "udp6-sendto", xioaddrs_udp6_sendto }, #endif #if WITH_UNIX - { "unix", &addr_unix_client }, - { "unix-client", &addr_unix_client }, - { "unix-connect", &addr_unix_connect }, + { "unix", xioaddrs_unix_client }, + { "unix-client", xioaddrs_unix_client }, + { "unix-connect", xioaddrs_unix_connect }, #endif #if WITH_UNIX && WITH_LISTEN - { "unix-l", &addr_unix_listen }, - { "unix-listen", &addr_unix_listen }, + { "unix-l", xioaddrs_unix_listen }, + { "unix-listen", xioaddrs_unix_listen }, #endif #if WITH_UNIX - { "unix-recv", &addr_unix_recv }, - { "unix-recvfrom", &addr_unix_recvfrom }, - { "unix-send", &addr_unix_sendto }, - { "unix-sendto", &addr_unix_sendto }, + { "unix-recv", xioaddrs_unix_recv }, + { "unix-recvfrom", xioaddrs_unix_recvfrom }, + { "unix-send", xioaddrs_unix_sendto }, + { "unix-sendto", xioaddrs_unix_sendto }, #endif #else /* !0 */ # if WITH_INTEGRATE @@ -255,8 +289,6 @@ const struct addrname addressnames[] = { { NULL } /* end marker */ } ; -int xioopen_single(xiofile_t *xfd, int xioflags); - /* prepares a xiofile_t record for dual address type: sets the tag and allocates memory for the substreams. @@ -268,13 +300,16 @@ int xioopen_makedual(xiofile_t *file) { if ((file->dual.stream[0] = (xiosingle_t *)xioallocfd()) == NULL) return -1; file->dual.stream[0]->flags = XIO_RDONLY; + file->dual.stream[0]->fdtype = FDTYPE_SINGLE; if ((file->dual.stream[1] = (xiosingle_t *)xioallocfd()) == NULL) return -1; file->dual.stream[1]->flags = XIO_WRONLY; + file->dual.stream[1]->fdtype = FDTYPE_SINGLE; return 0; } -static xiofile_t *xioallocfd(void) { +/* returns NULL if an error occurred */ +xiofile_t *xioallocfd(void) { xiofile_t *fd; if ((fd = Calloc(1, sizeof(xiofile_t))) == NULL) { @@ -294,12 +329,15 @@ static xiofile_t *xioallocfd(void) { /* fd->common.ignoreeof = false; */ /* fd->common.eof = 0; */ - fd->stream.fd = -1; + fd->stream.fd1 = -1; + fd->stream.fd2 = -1; + fd->stream.fdtype = FDTYPE_SINGLE; fd->stream.dtype = XIODATA_STREAM; #if WITH_SOCKET /* fd->stream.salen = 0; */ #endif /* WITH_SOCKET */ - fd->stream.howtoend = END_UNSPEC; +/* fd->stream.howtoshut = XIOSHUT_UNSPEC;*/ +/* fd->stream.howtoclose = XIOCLOSE_UNSPEC;*/ /* fd->stream.name = NULL; */ /* fd->stream.para.exec.pid = 0; */ fd->stream.lineterm = LINETERM_RAW; @@ -313,77 +351,532 @@ static xiofile_t *xioallocfd(void) { return fd; } - -/* parse the argument that specifies a two-directional data stream - and open the resulting address - */ -xiofile_t *xioopen(const char *addr, /* address specification */ - int xioflags) { - xiofile_t *xfd; - - if (xioinitialize() < 0) { - return NULL; +void xiofreefd(xiofile_t *xfd) { + if (xfd->stream.opts != NULL) { + dropopts(xfd->stream.opts, PH_ALL); } - - if ((xfd = xioparse_dual(&addr)) == NULL) { - return NULL; - } - if (xioopen_dual(xfd, xioflags) < 0) { - /*!!! free something? */ - return NULL; - } - - return xfd; + free(xfd); } -static xiofile_t *xioparse_dual(const char **addr) { + +/* handle one chain of addresses + dirs is one of XIO_RDWR, XIO_RDONLY, or XIO_WRONLY +*/ +xiofile_t *socat_open(const char *addrs0, int dirs, int flags) { + const char *addrs; + xiosingle_t *sfdA; /* what we just parse(d) */ + xiosingle_t *sfdB; /* what we just parse(d) - second part of dual */ + int newpipesep = 1; /* dual address: 1%0 instead of 0!!1 */ + int reverseA, reverseB=0; + bool currentisendpoint = false; + int mayleftA, mayrightA, mayleftB, mayrightB; + int isleftA, isrightA, isleftB, isrightB; + int srchleftA, srchrightA, srchleftB=0, srchrightB=0; + xiofile_t *xfd0; /* what we return */ + xiofile_t *xfd1; /* left hand of engine */ + xiofile_t *xfd2; /* return by sub address */ + int dirs0, dirs1, dirs2; /* the data directions for respective xfd */ + int xfd0shut; + int xfd0close; + int lefttoright[2]; + int righttoleft[2]; + struct threadarg_struct *thread_arg; + /*0 pthread_t thread = 0;*/ + /*pthread_attr_t attr;*/ + int _errno = 0; + + /* loop over retries */ + while (true) { + + addrs = addrs0; + skipsp(&addrs); + dirs0 = dirs; + + /* here we do not know much: will the next sub address be inter or + endpoint, single or dual, reverse? */ + + /* check the logical direction of the current subaddress */ + reverseA = !(strncmp(addrs, xioparams->reversechar, + strlen(xioparams->reversechar))); + if (reverseA) { + addrs += strlen(xioparams->reversechar); /* consume "reverse" */ + skipsp(&addrs); + } + + if ((sfdA = xioparse_single(&addrs)) == NULL) { + Error1("syntax error in \"%s\"", addrs); + return NULL; + } + skipsp(&addrs); + + /* is it a dual sub address? */ + if (!strncmp(addrs, xioparams->pipesep, strlen(xioparams->pipesep))) { + /* yes, found dual-address operator */ + if (dirs != XIO_RDWR) { + Error("dual address cannot handle single direction data stream"); + } + skipsp(&addrs); + addrs += strlen(xioparams->pipesep); /* consume "%" */ + /* check the logical direction of the current subaddress */ + skipsp(&addrs); + reverseB = !(strncmp(addrs, xioparams->reversechar, + strlen(xioparams->reversechar))); + if (reverseB) { + addrs += strlen(xioparams->reversechar); /* consume "reverse" */ + skipsp(&addrs); + } + + if ((sfdB = xioparse_single(&addrs)) == NULL) { + Error1("syntax error in \"%s\"", addrs); + return NULL; + } + skipsp(&addrs); + } else { + sfdB = NULL; + } + + /* is it the final sub address? */ + if (*addrs == '\0') { + currentisendpoint = true; + } else if (!strncmp(addrs, xioparams->chainsep, + strlen(xioparams->chainsep))) { + addrs += strlen(xioparams->chainsep); + skipsp(&addrs); + currentisendpoint = false; + } else { + Error2("syntax error on \"%s\": expected eol or \"%s\"", + addrs, xioparams->chainsep); + xiofreefd((xiofile_t *)sfdA); + if (sfdB != NULL) xiofreefd((xiofile_t *)sfdB); + return NULL; + } + + /* now we know the context of the current sub address: + currentisendpoint...it is an endpoint, not an inter address + sfdB.......if not null, we have a dual type address + reverseA...sfdA is reverse + reverseB...if dual address then sfdB is reverse + dirs0......the data directions of xfd0 */ + /* note: with dual inter, sfdB is implicitely reverse */ + + /* calculate context parameters that are easier to handle */ + if (sfdB == NULL) { + srchleftA = mayleftA = (1 << dirs0); + srchrightA = mayrightA = (currentisendpoint ? 0 : XIOBIT_ALL); + if (reverseA) { + /*srchrightA = XIOBIT_REVERSE(srchleftA);*/ + srchrightA = srchleftA; + srchleftA = XIOBIT_ALL; + } + } else { /* A is only part of dual */ + srchleftA = mayleftA = XIOBIT_WRONLY; + srchrightA = mayrightA = (currentisendpoint ? 0 : XIOBIT_RDONLY); + if (reverseA) { + srchleftA = XIOBIT_RDONLY; + srchrightA = XIOBIT_WRONLY; + } + srchleftB = mayleftB = (currentisendpoint ? XIOBIT_RDONLY : XIOBIT_WRONLY); + srchrightB = mayrightB = (currentisendpoint ? 0 : XIOBIT_RDONLY); + if (reverseB) { + srchleftB = XIOBIT_RDONLY; + srchrightB = XIOBIT_WRONLY; + } + } + + if (((dirs0+1) & (XIO_WRONLY+1)) || currentisendpoint) { + if (xioopen_unoverload(sfdA, srchleftA, &isleftA, srchrightA, &isrightA) + < 0) { + Error1("address \"%s\" can not be used in this context", + sfdA->addrdescs[0]->inter_desc.defname); + } + } else { + if (xioopen_unoverload(sfdA, srchrightA, &isrightA, srchleftA, &isleftA) + < 0) { + Error1("address \"%s\" can not be used in this context", + sfdA->addrdescs[0]->inter_desc.defname); + } + } + if (reverseA) { isrightA = isleftA; } + + if (sfdB != NULL) { + if (xioopen_unoverload(sfdB, srchleftB, &isleftB, srchrightB, &isrightB) + < 0) { + Error1("address \"%s\" can not be used in this context", + sfdB->addrdescs[0]->inter_desc.defname); + } + if (reverseB) { isleftB = XIOBIT_REVERSE(srchrightB); } + if (!currentisendpoint && ((isrightA+1) & (isleftB+1))) { + /* conflict in directions on right side (xfd1) */ + Error("conflict in data directions");/*!!*/ + } + dirs1 = ((isrightA+1) | (isleftB+1)) - 1; + } else { + dirs1 = isrightA; + } + dirs2 = (dirs1==XIO_RDWR) ? XIO_RDWR : (dirs1==XIO_RDONLY) ? XIO_WRONLY : + XIO_RDONLY; + + /* now we know exactly what to do with the current sub address */ + + /* we need the values for retry, forever, and intervall */ + applyopts_offset(sfdA, sfdA->opts); + if (sfdB != NULL) { + applyopts_offset(sfdB, sfdB->opts); + } + + if (currentisendpoint) { + if (sfdB != NULL) { + if ((xfd0 = xioallocfd()) == NULL) { + xiofreefd((xiofile_t *)sfdA); xiofreefd((xiofile_t *)sfdB); + return NULL; + } + xioopen_makedual(xfd0); + xfd0->dual.stream[0] = sfdB; + xfd0->dual.stream[1] = sfdA; + } else { + xfd0 = (xiofile_t *)sfdA; + } + /* open it and be ready in this thread */ + if (xioopen_endpoint_dual(xfd0, dirs0|flags) < 0) { + xiofreefd(xfd0); + return NULL; + } + return xfd0; + } + + /* the current addr is not the final sub address */ + + /* recursively open the following addresses of chain */ + /* loop over retries if appropriate */ + do { + xfd2 = socat_open(addrs, dirs2, flags); + if (xfd2 != NULL) { + break; /* succeeded */ + } + if (sfdA->retry == 0 && !sfdA->forever) { + xiofreefd((xiofile_t *)sfdA); + if (sfdB != NULL) xiofreefd((xiofile_t *)sfdB); + /*! close()? */ + return NULL; + } + Nanosleep(&sfdA->intervall, NULL); + if (sfdA->retry) --sfdA->retry; + } while (true); + + /* only xfd2 is valid here, contains a handle for the rest of the chain + */ + /* yupp, and the single addresses sfdA and ev.sfdB are valid too */ + + /* what are xfd0, xfd1, and xfd2? + consider chain: addr1|addr2 + with no reverse address, this will run like: + _socat(,addr1) --- _socat(-, addr2) + _socat(???, xfd0) --- _socat(xfd1,xfd2) + xfd0 will be opened in this routine + xfd1 will be assembled now, just using FDs + xfd2 comes from recursive open call + */ + /* but, with reverse, it looks so: + consider chain: ^addr1|addr2 + _socat(,-) --- _socat(addr1,addr2) + _socat(??? ,xfd0) --- _socat(xfd1, xfd2) + xfd0 will be assembled now, just using FDs + xfd1 was just initialized in this routine + xfd2 comes from recursive open call + */ + /* even worse, with mixed forward/reverse dual address: + consider chain: addr1a%^addr1b|addr2 + _socat(dual.stream[1] = sfdA; + sprintf(addr, "FD:%u", righttoleft[0]); + if ((xfd0->dual.stream[0] = + (xiosingle_t *)socat_open(addr, XIO_WRONLY, 0)) + == NULL) { + xiofreefd(xfd0); xiofreefd(xfd2); return NULL; + } + /* address type FD keeps the FDs open per default, but ... */ + + xfd1 = xioallocfd(); + xioopen_makedual(xfd1); + xfd1->dual.stream[1] = sfdB; + sprintf(addr, "FD:%u", lefttoright[0]); + if ((xfd1->dual.stream[0] = + (xiosingle_t *)socat_open(addr, XIO_RDONLY, 0)) + == NULL) { + xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2); + return NULL; + } + } else { + /* A is reverse, but B is not */ + char addr[15]; + + xfd0 = xioallocfd(); + xioopen_makedual(xfd0); + xfd0->dual.stream[0] = sfdB; + sprintf(addr, "FD:%u", lefttoright[1]); + if ((xfd0->dual.stream[1] = + (xiosingle_t *)socat_open(addr, XIO_RDONLY, 0)) + == NULL) { + xiofreefd(xfd0); xiofreefd(xfd2); return NULL; + } + + xfd1 = xioallocfd(); + xioopen_makedual(xfd1); + xfd1->dual.stream[0] = sfdA; + sprintf(addr, "FD:%u", righttoleft[1]); + if ((xfd1->dual.stream[1] = + (xiosingle_t *)socat_open(addr, XIO_RDONLY, 0)) + == NULL) { + xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2); + return NULL; + } + } + xfd0->dual.stream[0]->fd1 = lefttoright[1]; + xfd0->dual.stream[1]->fd1 = righttoleft[0]; + xfd1->dual.stream[0]->fd1 = righttoleft[1]; + xfd1->dual.stream[1]->fd1 = lefttoright[0]; + } else { + /* either dual with equal directions, or non-dual */ + xiofile_t *tfd; /* temp xfd */ + char addr[15]; + if (sfdB != NULL) { + /* dual, none or both are reverse */ + tfd = xioallocfd(); + xioopen_makedual(tfd); + tfd->dual.stream[1] = sfdA; + tfd->dual.stream[0] = sfdB; + } else { + /* non-dual */ + tfd = (xiofile_t *)sfdA; + } + + /* now take care of orientation */ + if (!reverseA) { + /* forward */ + xfd0 = tfd; + if (dirs1 == XIO_RDWR) { + sprintf(addr, "FD:%u:%u", righttoleft[1], lefttoright[0]); + } else if (dirs1 == XIO_RDONLY) { + sprintf(addr, "FD:%u", lefttoright[0]); + } else { + sprintf(addr, "FD:%u", righttoleft[1]); + } + if ((xfd1 = socat_open(addr, dirs1, 0)) == NULL) { + xiofreefd(xfd0); xiofreefd(xfd2); + return NULL; + } + } else { + /* reverse */ + xfd1 = tfd; + if (dirs0 == XIO_RDWR) { + sprintf(addr, "FD:%u:%u", lefttoright[1], righttoleft[0]); + } else if (dirs0 == XIO_RDONLY) { + sprintf(addr, "FD:%u", righttoleft[0]); + } else { + sprintf(addr, "FD:%u", lefttoright[1]); + } + if ((xfd0 = socat_open(addr, XIO_RDWR, 0)) == NULL) { + xiofreefd(xfd1); xiofreefd(xfd2); + return NULL; + } + /* address type FD keeps the FDs open per default, but ... */ + } + if (xfd0->tag == XIO_TAG_DUAL) { + xfd0->dual.stream[0]->fd1 = lefttoright[1]; + xfd0->dual.stream[1]->fd1 = righttoleft[0]; + } else { + xfd0->stream.fd1 = righttoleft[0]; + xfd0->stream.fd2 = lefttoright[1]; + } + if (xfd1->tag == XIO_TAG_DUAL) { + xfd1->dual.stream[0]->fd1 = righttoleft[1]; + xfd1->dual.stream[1]->fd1 = lefttoright[0]; + } else { + xfd1->stream.fd1 = lefttoright[0]; + xfd1->stream.fd2 = righttoleft[1]; + } + } + + /* address type FD keeps the FDs open per default, but ... */ + if (xfd0->tag == XIO_TAG_DUAL) { + xfd0->dual.stream[0]->howtoshut = xfd0shut; + xfd0->dual.stream[0]->howtoclose = xfd0close; + xfd0->dual.stream[1]->howtoshut = xfd0shut; + xfd0->dual.stream[1]->howtoclose = xfd0close; + } else { + xfd0->stream.howtoshut = xfd0shut; + xfd0->stream.howtoclose = xfd0close; + } + if (xfd1->tag == XIO_TAG_DUAL) { + xfd1->dual.stream[0]->howtoshut = xfd0shut; + xfd1->dual.stream[0]->howtoclose = xfd0close; + xfd1->dual.stream[1]->howtoshut = xfd0shut; + xfd1->dual.stream[1]->howtoclose = xfd0close; + } else { + xfd1->stream.howtoshut = xfd0shut; + xfd1->stream.howtoclose = xfd0close; + } + + /* here xfd2 is valid and ready for transfer; + and xfd0 and xfd1 are valid and ready for opening */ + + if ((thread_arg = Malloc(sizeof(struct threadarg_struct))) == NULL) { + /*! free something */ + xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2); + return NULL; + } + thread_arg->xfd1 = xfd1; + thread_arg->xfd2 = xfd2; + if ((_errno = + Pthread_create(&xfd0->stream.subthread, NULL, + (reverseA||(sfdB!=NULL)&&!reverseB)?xioopenleftthenengine:xioengine, + thread_arg)) + != 0) { + Error4("pthread_create(%p, {}, xioengine, {%p,%p}): %s", + &xfd0->stream.subthread, thread_arg->xfd1, thread_arg->xfd2, + strerror(_errno)); + xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2); + free(thread_arg); return NULL; + } + Info1("started thread "F_thread, xfd0->stream.subthread); + xfd1 = NULL; + xfd2 = NULL; + + /* open protocol part */ + if (xioopen_inter_dual(xfd0, dirs|flags) + < 0) { + /*! close sub chain */ + if (xfd0->stream.retry == 0 && !xfd0->stream.forever) { + xiofreefd(xfd0); /*! close()? */ return NULL; + } + Nanosleep(&xfd0->stream.intervall, NULL); + if (xfd0->stream.retry) --xfd0->stream.retry; + continue; + } + break; + } + /*!!!?*/ +#if 0 + xfd0->stream.howtoshut = XIOSHUT_CLOSE; +#endif + return xfd0; +} + +void *xioopenleftthenengine(void *thread_void) { + struct threadarg_struct *thread_arg = thread_void; + xiofile_t *xfd1 = thread_arg->xfd1; + xiofile_t *xfd2 = thread_arg->xfd2; + + /*! design a function with better interface */ + if (xioopen_inter_dual(xfd1, XIO_RDWR|XIO_MAYCONVERT) < 0) { + xioclose(xfd2); + xiofreefd(xfd1); + xiofreefd(xfd2); + return NULL; + } + xioengine(thread_void); + return NULL; +} + + +xiofile_t *xioparse_dual(const char **addr) { xiofile_t *xfd; xiosingle_t *sfd1; + int reverse; + + /* check the logical direction of the current subaddress */ + reverse = !(strncmp(*addr, xioparams->reversechar, + strlen(xioparams->reversechar))); + if (reverse) { + /* skip "reverse" token */ + *addr += strlen(xioparams->reversechar); + } /* we parse a single address */ if ((sfd1 = xioparse_single(addr)) == NULL) { return NULL; } + sfd1->reverse = reverse; /* and now we see if we reached a dual-address separator */ - if (!strncmp(*addr, xioopts.pipesep, strlen(xioopts.pipesep))) { - /* yes we reached it, so we parse the second single address */ - *addr += strlen(xioopts.pipesep); - - if ((xfd = xioallocfd()) == NULL) { - free(sfd1); /*! and maybe have free some if its contents */ - return NULL; - } - xfd->tag = XIO_TAG_DUAL; - xfd->dual.stream[0] = sfd1; - if ((xfd->dual.stream[1] = xioparse_single(addr)) == NULL) { - return NULL; - } - - return xfd; + if (strncmp(*addr, xioopts.pipesep, strlen(xioopts.pipesep))) { + /* no, finish */ + return (xiofile_t *)sfd1; } - /* a truly single address */ - xfd = (xiofile_t *)sfd1; sfd1 = NULL; + /* we found the dual-address operator, so we parse the second single address + */ + *addr += strlen(xioparams->pipesep); + if ((xfd = xioallocfd()) == NULL) { + xiofreefd((xiofile_t *)sfd1); + return NULL; + } + xfd->tag = XIO_TAG_DUAL; + xfd->dual.stream[0] = sfd1; + if ((xfd->dual.stream[1] = xioparse_single(addr)) == NULL) { + xiofreefd(xfd); /*! and maybe have free some if its contents */ + return NULL; + } + return xfd; } -static int xioopen_dual(xiofile_t *xfd, int xioflags) { +int xioopen_inter_dual(xiofile_t *xfd, int xioflags) { if (xfd->tag == XIO_TAG_DUAL) { /* a really dual address */ if ((xioflags&XIO_ACCMODE) != XIO_RDWR) { Warn("unidirectional open of dual address"); } + + /* a "usual" bidirectional stream specification, one address */ if (((xioflags&XIO_ACCMODE)+1) & (XIO_RDONLY+1)) { - if (xioopen_single((xiofile_t *)xfd->dual.stream[0], XIO_RDONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC)) + if (xioopen_inter_single((xiofile_t *)xfd->dual.stream[0], XIO_RDONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC)) < 0) { return -1; } } + /*! should come before xioopensingle? */ if (((xioflags&XIO_ACCMODE)+1) & (XIO_WRONLY+1)) { - if (xioopen_single((xiofile_t *)xfd->dual.stream[1], XIO_WRONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC)) + if (xioopen_inter_single((xiofile_t *)xfd->dual.stream[1], XIO_WRONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC)) < 0) { xioclose((xiofile_t *)xfd->dual.stream[0]); return -1; @@ -392,15 +885,51 @@ static int xioopen_dual(xiofile_t *xfd, int xioflags) { return 0; } - return xioopen_single(xfd, xioflags); + return xioopen_inter_single(xfd, xioflags); +} + +int xioopen_endpoint_dual(xiofile_t *xfd, int xioflags) { + + if (xfd->tag == XIO_TAG_DUAL) { + /* a really dual address */ + if ((xioflags&XIO_ACCMODE) != XIO_RDWR) { + Warn("unidirectional open of dual address"); + } + + /* a "usual" bidirectional stream specification, one address */ + if (((xioflags&XIO_ACCMODE)+1) & (XIO_WRONLY+1)) { + if (xioopen_endpoint_single((xiofile_t *)xfd->dual.stream[1], XIO_WRONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC)) + < 0) { + return -1; + } + } + /*! should come before xioopensingle? */ + if (((xioflags&XIO_ACCMODE)+1) & (XIO_RDONLY+1)) { + if (xioopen_endpoint_single((xiofile_t *)xfd->dual.stream[0], XIO_RDONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC)) + < 0) { + xioclose((xiofile_t *)xfd->dual.stream[1]); + return -1; + } + } + return 0; + } + + return xioopen_endpoint_single(xfd, xioflags); } -static xiosingle_t *xioparse_single(const char **addr) { +/* parses the parameters and options of a single (sub)address. + returns 0 on success or -1 if an error occurred. */ +static xiosingle_t * + xioparse_single(const char **addr /* input string; afterwards points to + first char not belonging to this + sub address */ + ) { + char addr0[20]; xiofile_t *xfd; xiosingle_t *sfd; - struct addrname *ae; - const struct addrdesc *addrdesc = NULL; + struct xioaddrname *ae; + /*int maxparams;*/ /* max number of parameters */ const char *ends[4+1]; const char *hquotes[] = { "'", @@ -423,8 +952,8 @@ static xiosingle_t *xioparse_single(const char **addr) { /* init */ i = 0; - /*ends[i++] = xioopts.chainsep;*/ /* default: "|" */ - ends[i++] = xioopts.pipesep; /* default: "!!" */ + ends[i++] = xioopts.chainsep; /* default: "|" */ + ends[i++] = xioopts.pipesep; /* default: "%" */ ends[i++] = ","/*xioopts.comma*/; /* default: "," */ ends[i++] = ":"/*xioopts.colon*/; /* default: ":" */ ends[i++] = NULL; @@ -435,29 +964,32 @@ static xiosingle_t *xioparse_single(const char **addr) { sfd = &xfd->stream; sfd->argc = 0; + /* for error messages */ + strncpy(addr0, *addr, sizeof(addr0)-1); + addr0[sizeof(addr0)-1] = '\0'; + len = sizeof(token); tokp = token; if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests, - true, true, false) < 0) { + true, true, true, false) < 0) { Error2("keyword too long, in address \"%s%s\"", token, *addr); } *tokp = '\0'; /*! len? */ - ae = (struct addrname *) - keyw((struct wordent *)&addressnames, token, - sizeof(addressnames)/sizeof(struct addrname)-1); - - if (ae) { - addrdesc = ae->desc; - /* keyword */ + ae = (struct xioaddrname *) + keyw((struct wordent *)&address_names, token, + sizeof(address_names)/sizeof(struct xioaddrname)-1); + if (ae != NULL) { + /* found keyword */ + sfd->addrdescs = ae->desc; if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) { Error1("strdup(\"%s\"): out of memory", token); } } else { - if (false) { + if (false) { /* for canonical reasons */ ; #if WITH_FDNUM } else if (isdigit(token[0]&0xff) && token[1] == '\0') { Info1("interpreting address \"%s\" as file descriptor", token); - addrdesc = &addr_fd; + sfd->addrdescs = xioaddrs_fdnum; if ((sfd->argv[sfd->argc++] = strdup("FD")) == NULL) { Error("strdup(\"FD\"): out of memory"); } @@ -469,7 +1001,7 @@ static xiosingle_t *xioparse_single(const char **addr) { #if WITH_GOPEN } else if (strchr(token, '/')) { Info1("interpreting address \"%s\" as file name", token); - addrdesc = &addr_gopen; + sfd->addrdescs = xioaddrs_gopen; if ((sfd->argv[sfd->argc++] = strdup("GOPEN")) == NULL) { Error("strdup(\"GOPEN\"): out of memory"); } @@ -480,18 +1012,20 @@ static xiosingle_t *xioparse_single(const char **addr) { #endif /* WITH_GOPEN */ } else { Error1("unknown device/address \"%s\"", token); - /*!!! free something*/ return NULL; + xiofreefd(xfd); + return NULL; } } - sfd->tag = XIO_TAG_RDWR; - sfd->addr = addrdesc; - while (!strncmp(*addr, xioopts.paramsep, strlen(xioopts.paramsep))) { + if (sfd->argc >= MAXARGV) { + Error1("address \"%s\": succeeds max number of parameters", + sfd->argv[0]); + } *addr += strlen(xioopts.paramsep); len = sizeof(token); tokp = token; if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests, - true, true, false) != 0) { + true, true, true, false) != 0) { Error2("syntax error in address \"%s%s\"", token, *addr); } *tokp = '\0'; @@ -500,30 +1034,105 @@ static xiosingle_t *xioparse_single(const char **addr) { } } - if (parseopts(addr, addrdesc->groups, &sfd->opts) < 0) { - free(xfd); + if (parseopts(addr, &sfd->opts) < 0) { + xiofreefd(xfd); return NULL; } return sfd; } -int xioopen_single(xiofile_t *xfd, int xioflags) { - const struct addrdesc *addrdesc; +/* during parsing the sub address, we did not know if it is used as inter + address or endpoint; therefore we could not select the appropriate address + descriptor. Here we already know the context and thus select the address + descriptor and check the option groups. + returns 0 on success or -1 if an error occurred */ +static int + xioopen_unoverload(xiosingle_t *sfd, + int mayleft, /* what may be on left side: or'd + XIOBIT_RDWR, XIOBIT_RDONLY, + XIOBIT_WRONLY */ + int *isleft, /* what the selected address desc + provides on left side: XIO_RDWR, + XIO_RDONLY, or XIO_WRONLY */ + int mayright, /* what may be on right side: or'd + XIOBIT_RDWR, XIOBIT_RDONLY, + XIOBIT_WRONLY */ + int *isright) /* what the selected address desc + provides on right side: XIO_RDWR, + XIO_RDONLY, or XIO_WRONLY */ +{ + const union xioaddr_desc **addrdescs; + int tag; + int i; + + addrdescs = sfd->addrdescs; + tag = (mayright ? XIOADDR_INTER : XIOADDR_ENDPOINT); + + /* look for a matching entry in the list of address descriptions */ + while ((*addrdescs) != NULL) { + if ((*addrdescs)->tag == tag && + addrdescs[0]->common_desc.numparams == sfd->argc-1 && + (addrdescs[0]->common_desc.leftdirs & mayleft) != 0 && + (mayright ? (addrdescs[0]->inter_desc.rightdirs & mayright) : 1)) { + break; + } + ++addrdescs; + } + + if (addrdescs[0] == NULL) { + Error3("address \"%s...\" in %s context and with %d parameter(s) is not defined", + sfd->argv[0], tag==XIOADDR_ENDPOINT?"endpoint":"intermediate", + sfd->argc-1); + xiofreefd((xiofile_t *)sfd); return -1; + } + + i = (addrdescs[0]->common_desc.leftdirs & mayleft); + *isleft = 0; + while (i>>=1) { + ++*isleft; + } + if (true /*0 mayright*/) { + i = (addrdescs[0]->inter_desc.rightdirs & mayright); + *isright = 0; + while (i>>=1) { + ++*isright; + } + } + sfd->tag = (*isleft + 1); + sfd->addrdesc = addrdescs[0]; + sfd->howtoshut = addrdescs[0]->common_desc.howtoshut; + sfd->howtoclose = addrdescs[0]->common_desc.howtoclose; + + return 0; +} + + +static int + xioopen_inter_single(xiofile_t *xfd, int xioflags) { + const struct xioaddr_inter_desc *addrdesc; int result; + addrdesc = &xfd->stream.addrdesc->inter_desc; + if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) { xfd->tag = XIO_TAG_RDONLY; + xfd->stream.fdtype = FDTYPE_SINGLE; } else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) { xfd->tag = XIO_TAG_WRONLY; + xfd->stream.fdtype = FDTYPE_SINGLE; } else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) { xfd->tag = XIO_TAG_RDWR; + if (xfd->stream.fd2 >= 0) { + xfd->stream.fdtype = FDTYPE_DOUBLE; + } else { + xfd->stream.fdtype = FDTYPE_SINGLE; + } } else { Error1("invalid mode for address \"%s\"", xfd->stream.argv[0]); } xfd->stream.flags &= (~XIO_ACCMODE); xfd->stream.flags |= (xioflags & XIO_ACCMODE); - addrdesc = xfd->stream.addr; result = (*addrdesc->func)(xfd->stream.argc, xfd->stream.argv, xfd->stream.opts, xioflags, xfd, addrdesc->groups, addrdesc->arg1, @@ -531,3 +1140,28 @@ int xioopen_single(xiofile_t *xfd, int xioflags) { return result; } +static int + xioopen_endpoint_single(xiofile_t *xfd, int xioflags) { + const struct xioaddr_endpoint_desc *addrdesc; + int result; + + addrdesc = &xfd->stream.addrdesc->endpoint_desc; + if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) { + xfd->tag = XIO_TAG_RDONLY; + xfd->stream.fdtype = FDTYPE_SINGLE; + } else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) { + xfd->tag = XIO_TAG_WRONLY; + xfd->stream.fdtype = FDTYPE_SINGLE; + } else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) { + xfd->tag = XIO_TAG_RDWR; + } else { + Error1("invalid mode for address \"%s\"", xfd->stream.argv[0]); + } + xfd->stream.flags &= (~XIO_ACCMODE); + xfd->stream.flags |= (xioflags & XIO_ACCMODE); + result = (*addrdesc->func)(xfd->stream.argc, xfd->stream.argv, + xfd->stream.opts, xioflags, xfd, + addrdesc->groups, addrdesc->arg1, + addrdesc->arg2, addrdesc->arg3); + return result; +} diff --git a/xioopen.h b/xioopen.h index 7578b64..9c53ccf 100644 --- a/xioopen.h +++ b/xioopen.h @@ -1,5 +1,5 @@ -/* $Id: xioopen.h,v 1.22 2006/05/12 20:14:05 gerhard Exp $ */ -/* Copyright Gerhard Rieger 2001-2006 */ +/* $Id: xioopen.h,v 1.22.2.1 2006/07/24 19:26:29 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xioopen_h_included @@ -33,16 +33,25 @@ extern const struct optdesc opt_tabdly; extern const struct optdesc opt_csize; -struct addrname { +struct xioaddrname { 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 *filetypenames[]; -extern const struct addrname addressnames[]; +extern const struct xioaddrname address_names[]; 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); #define retropt_2bytes(o,c,r) retropt_ushort(o,c,r) diff --git a/xioopts.c b/xioopts.c index d84b138..f494a02 100644 --- a/xioopts.c +++ b/xioopts.c @@ -88,6 +88,12 @@ bool xioopts_ignoregroups; # define IF_SOCKS4(a,b) #endif +#if WITH_SOCKS5 +# define IF_SOCKS5(a,b) {a,b}, +#else +# define IF_SOCKS5(a,b) +#endif + #if WITH_PROXY # define IF_PROXY(a,b) {a,b}, #else @@ -1190,6 +1196,7 @@ const struct optname optionnames[] = { #endif IF_ANY ("setuid", &opt_setuid) IF_ANY ("setuid-early", &opt_setuid_early) + IF_ANY ("shut-none", &opt_shut_none) #if WITH_EXEC || WITH_SYSTEM IF_ANY ("sid", &opt_setsid) #endif @@ -1302,6 +1309,8 @@ const struct optname optionnames[] = { #ifdef SO_USELOOPBACK /* AIX433, Solaris */ IF_SOCKET ("so-useloopback", &opt_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 ("socksuser", &opt_socksuser) IF_IPAPP ("sourceport", &opt_sourceport) @@ -1560,9 +1569,9 @@ const struct optname optionnames[] = { to the array opts. Uses the option table 'optionnames'. 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); } @@ -1571,7 +1580,7 @@ int parseopts(const char **a, unsigned int groups, struct opt **opts) { to the array opts. Uses the specified option table. 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) { int i=0; struct opt *opt; @@ -1603,15 +1612,15 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts, } ; i = 0; - /*endkey[i++] = xioopts.chainsep;*/ /* default: "|" */ - endkey[i++] = xioopts.pipesep; /* default: "!!" */ + endkey[i++] = xioopts.chainsep; /* default: "|" */ + endkey[i++] = xioopts.pipesep; /* default: "%" */ endkey[i++] = ","/*xioopts.comma*/; /* default: "," */ endkey[i++] = "="; endkey[i++] = NULL; i = 0; - /*endval[i++] = xioopts.chainsep;*/ /* default: "|" */ - endval[i++] = xioopts.pipesep; /* default: "!!" */ + endval[i++] = xioopts.chainsep; /* default: "|" */ + endval[i++] = xioopts.pipesep; /* default: "%" */ endval[i++] = ","/*xioopts.comma*/; /* default: "," */ endval[i++] = NULL; @@ -1637,7 +1646,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts, len = sizeof(token); tokp = token; parsres = nestlex(a, &tokp, &len, endkey, hquotes, squotes, nests, - true, true, false); + true, true, true, false); if (parsres != 0) { return -1; } @@ -1654,6 +1663,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts, continue; } +#if 0 if (!(ent->desc->group & groups) && !(ent->desc->group & GROUP_ANY) && !xioopts_ignoregroups) { 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; #endif } +#endif (*opts)[i].desc = ent->desc; 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; parsres = nestlex(a, &tokp, &len, endval, hquotes, squotes, nests, - true, true, false); + true, true, true, false); if (parsres != 0) { return -1; } @@ -1981,7 +1992,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts, /*! result= */ nestlex((const char **)&tokp, &buffp, &bufspc, ends, NULL, NULL, nests, - true, false, false); + true, true, false, false); if (*tokp != ':') { Error1("syntax in option %s: missing ':'", token); } @@ -1994,7 +2005,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts, /*! result= */ nestlex((const char **)&tokp, &buffp, &bufspc, ends, NULL, NULL, nests, - true, false, false); + true, true, false, false); *buffp++ = '\0'; (*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; nestlex((const char **)&tokp, &buffp, &bufspc, ends, NULL, NULL, nests, - true, false, false); + true, true, false, false); if (*tokp != '\0') { 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; } + +/* 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 matching groups ANY and */ struct opt *copyopts(const struct opt *opts, unsigned int groups) { @@ -2479,7 +2516,7 @@ int retropt_bind(struct opt *opts, portallowed = (feats>=2); bindp = bindname; nestlex((const char **)&bindp, &hostp, &hostlen, ends, NULL, NULL, nests, - true, false, false); + true, true, false, false); *hostp++ = '\0'; if (!strncmp(bindp, portsep, strlen(portsep))) { if (!portallowed) { @@ -2591,7 +2628,8 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) { long mask = opt->desc->arg3; 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)); opt->desc = ODESC_ERROR; ++opt; continue; } @@ -3339,6 +3377,8 @@ static int applyopt_offset(struct single *xfd, struct opt *opt) { switch (opt->desc->type) { case TYPE_BOOL: *(bool *)ptr = opt->value.u_bool; break; + case TYPE_UINT: + *(unsigned int *)ptr = opt->value.u_uint; break; case TYPE_DOUBLE: *(double *)ptr = opt->value.u_double; break; case TYPE_TIMEVAL: @@ -3358,6 +3398,8 @@ static int applyopt_offset(struct single *xfd, struct opt *opt) { case TYPE_CONST: *(int *)ptr = opt->desc->minor; break; + case TYPE_TIMESPEC: + *(struct timespec *)ptr = opt->value.u_timespec; break; default: Error1("applyopt_offset(): type %d not implemented", opt->desc->type); @@ -3574,10 +3616,10 @@ mc:addr #endif #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) { 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_address.s_addr, ip4_mreqn.mreqn.imr_ifindex, @@ -3586,10 +3628,10 @@ mc:addr opt->desc = ODESC_ERROR; continue; } #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) { 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_interface, sizeof(ip4_mreqn.mreq), @@ -3626,10 +3668,10 @@ mc:addr 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) { 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, sizeof(ip6_mreq), strerror(errno)); @@ -3668,7 +3710,7 @@ int applyopts_signal(struct single *xfd, struct opt *opts) { ++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_DONE; @@ -3685,15 +3727,23 @@ int _xio_openlate(struct single *fd, struct opt *opts) { _xioopen_setdelayeduser(); - if ((result = applyopts(fd->fd, opts, PH_LATE)) < 0) { + if ((result = applyopts(fd->fd1, opts, PH_LATE)) < 0) { 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) { return result; } - if ((result = applyopts(fd->fd, opts, PH_LATE2)) < 0) { + if ((result = applyopts(fd->fd1, opts, PH_LATE2)) < 0) { return result; } + /*! need to apply to fd2 too! */ if ((numleft = leftopts(opts)) > 0) { showleft(opts); diff --git a/xioopts.h b/xioopts.h index 7d13ea5..b2f1da2 100644 --- a/xioopts.h +++ b/xioopts.h @@ -145,6 +145,7 @@ enum e_func { #define GROUP_PROCESS 0x10000000 /* a process related option */ #define GROUP_APPL 0x20000000 /* option handled by data loop */ #define GROUP_HTTP 0x40000000 /* any HTTP client */ +#define GROUP_SOCKS5 0x80000000 #define GROUP_ANY (GROUP_PROCESS|GROUP_APPL) #define GROUP_ALL 0xffffffff @@ -533,6 +534,7 @@ enum e_optcode { OPT_SETSID, OPT_SETUID, OPT_SETUID_EARLY, + OPT_SHUT_NONE, OPT_SIGHUP, OPT_SIGINT, OPT_SIGQUIT, @@ -630,6 +632,8 @@ enum e_optcode { #ifdef SO_USE_IFBUFS OPT_SO_USE_IFBUFS, #endif /* SO_USE_IFBUFS */ + OPT_SOCKS5_PASSWORD, + OPT_SOCKS5_USERNAME, #if 1 || defined(WITH_SOCKS4) OPT_SOCKSPORT, 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_signal(struct single *xfd, 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_table(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, struct opt **opts, 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 *moveopts(struct opt *opts, unsigned int groups); extern int leftopts(const struct opt *opts); diff --git a/xioparam.c b/xioparam.c index 4cbd11d..83f4301 100644 --- a/xioparam.c +++ b/xioparam.c @@ -1,5 +1,5 @@ /* $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 */ /* this file contains the source for xio options handling */ @@ -12,16 +12,28 @@ /* options that can be applied to this module */ xioopts_t xioopts = { false, /* strictopts */ - "!!", /* pipesep */ + "%", /* pipesep */ ":", /* paramsep */ ",", /* optionsep */ ':', /* ip4portsep */ ':', /* ip6portsep */ - '\0', /* logopt */ NULL, /* syslogfac */ '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 */ diff --git a/xioread.c b/xioread.c index 9d8b94d..8347977 100644 --- a/xioread.c +++ b/xioread.c @@ -9,6 +9,7 @@ #include "xio-termios.h" #include "xio-socket.h" +#include "xio-test.h" #include "xio-readline.h" #include "xio-openssl.h" @@ -21,6 +22,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) { int nexthead; #endif struct single *pipe; + int fd; int _errno; 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) { case XIOREAD_STREAM: do { - bytes = Read(pipe->fd, buff, bufsiz); + bytes = Read(fd, buff, bufsiz); } while (bytes < 0 && errno == EINTR); if (bytes < 0) { _errno = errno; @@ -61,12 +65,30 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) { #if 1 case EPIPE: case ECONNRESET: Warn4("read(%d, %p, "F_Zu"): %s", - pipe->fd, buff, bufsiz, strerror(_errno)); + fd, buff, bufsiz, strerror(_errno)); break; #endif default: 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; return -1; @@ -75,17 +97,17 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) { case XIOREAD_PTY: do { - bytes = Read(pipe->fd, buff, bufsiz); + 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)", - pipe->fd, buff, bufsiz, strerror(_errno)); + fd, buff, bufsiz, strerror(_errno)); return 0; } else { Error4("read(%d, %p, "F_Zu"): %s", - pipe->fd, buff, bufsiz, strerror(_errno)); + fd, buff, bufsiz, strerror(_errno)); } errno = _errno; return -1; @@ -100,6 +122,15 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) { break; #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 case XIOREAD_OPENSSL: /* this function prints its error messages */ @@ -118,14 +149,13 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) { char infobuff[256]; do { - bytes = - Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); + bytes = Recvfrom(fd, buff, bufsiz, 0, &from.soa, &fromlen); } while (bytes < 0 && errno == EINTR); if (bytes < 0) { char infobuff[256]; _errno = errno; 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)), fromlen, strerror(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; #endif if (headlen > bytes) { - Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd); + Warn1("xioread(%d, ...)/IP4: short packet", fd); bytes = 0; } else { 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); /* get source address */ - if (xiogetpacketsrc(pipe->fd, &from, &fromlen) < 0) { + if (xiogetpacketsrc(fd, &from, &fromlen) < 0) { return STAT_RETRYNOW; } 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; } Info1("permitting packet from %s", @@ -299,13 +329,13 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) { do { bytes = - Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); + Recvfrom(fd, buff, bufsiz, 0, &from.soa, &fromlen); } while (bytes < 0 && errno == EINTR); if (bytes < 0) { char infobuff[256]; _errno = errno; 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)), fromlen, strerror(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; #endif if (headlen > bytes) { - Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd); + Warn1("xioread(%d, ...)/IP4: short packet", fd); bytes = 0; } else { memmove(buff, ((char *)buff)+headlen, bytes-headlen); diff --git a/xioshutdown.c b/xioshutdown.c index 8e2ddb9..a90606f 100644 --- a/xioshutdown.c +++ b/xioshutdown.c @@ -8,6 +8,9 @@ #include "xiosysincludes.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 void signal_kill_pid(int dummy) { @@ -15,15 +18,21 @@ static void signal_kill_pid(int dummy) { Kill(socat_kill_pid, SIGTERM); } +/* how: SHUT_RD, SHUT_WR, or SHUT_RDWR */ int xioshutdown(xiofile_t *sock, int how) { 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) { Error("xioshutdown(): invalid file descriptor"); errno = EINVAL; 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 ((how+1)&1) { result = xioshutdown((xiofile_t *)sock->dual.stream[0], 0); @@ -31,104 +40,182 @@ int xioshutdown(xiofile_t *sock, int how) { if ((how+1)&2) { 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; } + + /* 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 (sock->stream.ttyvalid) { - if (Tcsetattr(sock->stream.fd, 0, &sock->stream.savetty) < 0) { - Warn2("cannot restore terminal settings on fd %d: %s", - sock->stream.fd, strerror(errno)); + if (sock->stream.ttyvalid) { + if (Tcsetattr(sock->stream.fd1, 0, &sock->stream.savetty) < 0) { + Warn2("cannot restore terminal settings on fd %d: %s", + sock->stream.fd1, strerror(errno)); + } + } +#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; } } -#endif /* WITH_TERMIOS */ + + 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 + 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; } + +/* 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; +} diff --git a/xiosigchld.c b/xiosigchld.c index 39c03f9..f23e617 100644 --- a/xiosigchld.c +++ b/xiosigchld.c @@ -1,5 +1,5 @@ /* $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 */ /* this is the source of the extended child signal handler */ @@ -7,23 +7,42 @@ #include "xiosysincludes.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 diedunknown2; pid_t diedunknown3; pid_t diedunknown4; +#endif /* register for a xio filedescriptor a callback (handler). when a SIGCHLD occurs, the signal handler will ??? */ int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)) { if (xfd->tag != XIO_TAG_DUAL) { - xfd->stream.sigchild = callback; + xfd->stream.child.sigchild = callback; } else { - xfd->dual.stream[0]->sigchild = callback; - xfd->dual.stream[1]->sigchild = callback; + xfd->dual.stream[0]->child.sigchild = callback; + xfd->dual.stream[1]->child.sigchild = callback; } 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 */ static int sigchld_stream(struct single *file) { /*!! call back to application */ - file->para.exec.pid = 0; - if (file->sigchild) { - return (*file->sigchild)(file); + file->child.pid = 0; + if (file->child.sigchild) { + return (*file->child.sigchild)(file); } return 0; } @@ -43,12 +62,9 @@ static int xio_checkchild(xiofile_t *socket, int socknum, pid_t deadchild) { int retval; if (socket != NULL) { if (socket->tag != XIO_TAG_DUAL) { - if ((socket->stream.howtoend == END_KILL || - socket->stream.howtoend == END_CLOSE_KILL || - socket->stream.howtoend == END_SHUTDOWN_KILL) && - socket->stream.para.exec.pid == deadchild) { + if (socket->stream.child.pid == deadchild) { Info2("exec'd process %d on socket %d terminated", - socket->stream.para.exec.pid, socknum); + socket->stream.child.pid, socknum); sigchld_stream(&socket->stream); 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 */ /* the current socat/xio implementation knows two kinds of children: - exec/system addresses perform a fork: these children are registered and - there death influences the parents flow; + exec/system addresses perform a fork: their children are registered and + their death's influence the parents' flow; listen-socket with fork children: these children are "anonymous" and their death does not affect the parent process (now; maybe we have a child 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; int _errno; int status = 0; bool wassig = false; int i; + struct _xiosigchld_child *entry; _errno = errno; /* save current value; e.g., select() on Cygwin seems to set it to EINTR _before_ handling the signal, and @@ -105,6 +126,7 @@ void childdied(int signum) { errno = _errno; return; } +#if 0 /*! indent */ /* check if it was a registered child process */ i = 0; @@ -128,6 +150,15 @@ void childdied(int signum) { 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 (WEXITSTATUS(status) == 0) { @@ -157,3 +188,107 @@ void childdied(int signum) { Info("childdied() finished"); 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); + } +} + diff --git a/xiosigchld.h b/xiosigchld.h new file mode 100644 index 0000000..8b28f76 --- /dev/null +++ b/xiosigchld.h @@ -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) */ diff --git a/xiosocketpair.c b/xiosocketpair.c new file mode 100644 index 0000000..5ae374a --- /dev/null +++ b/xiosocketpair.c @@ -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; +} + diff --git a/xiostatic.h b/xiostatic.h new file mode 100644 index 0000000..dc2c851 --- /dev/null +++ b/xiostatic.h @@ -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) */ diff --git a/xiotransfer.c b/xiotransfer.c new file mode 100644 index 0000000..dfd4f5b --- /dev/null +++ b/xiotransfer.c @@ -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; +} diff --git a/xiowrite.c b/xiowrite.c index d5e0cce..179e855 100644 --- a/xiowrite.c +++ b/xiowrite.c @@ -8,6 +8,7 @@ #include "xiosysincludes.h" #include "xioopen.h" +#include "xio-test.h" #include "xio-readline.h" #include "xio-openssl.h" @@ -20,6 +21,7 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) { ssize_t writt; struct single *pipe; + int fd; int _errno; 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 */ + fd = XIO_GETWRFD(file); + switch (pipe->dtype & XIODATA_WRITEMASK) { case XIOWRITE_STREAM: do { - writt = Write(pipe->fd, buff, bytes); + writt = Write(fd, buff, bytes); } while (writt < 0 && errno == EINTR); if (writt < 0) { _errno = errno; @@ -59,13 +63,13 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) { case ECONNRESET: if (pipe->cool_write) { Notice4("write(%d, %p, "F_Zu"): %s", - pipe->fd, buff, bytes, strerror(_errno)); + fd, buff, bytes, strerror(_errno)); break; } /*PASSTRHOUGH*/ default: Error4("write(%d, %p, "F_Zu"): %s", - pipe->fd, buff, bytes, strerror(_errno)); + fd, buff, bytes, strerror(_errno)); } errno = _errno; return -1; @@ -85,14 +89,14 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) { /*socklen_t fromlen;*/ do { - writt = Sendto(pipe->fd, buff, bytes, 0, + writt = Sendto(fd, buff, bytes, 0, &pipe->peersa.soa, pipe->salen); } while (writt < 0 && errno == EINTR); if (writt < 0) { char infobuff[256]; _errno = errno; 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, infobuff, sizeof(infobuff)), 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) { char infobuff[256]; 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, infobuff, sizeof(infobuff)), pipe->salen, writt, bytes); @@ -112,7 +116,7 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) { char infobuff[256]; union sockaddr_union us; socklen_t uslen = sizeof(us); - Getsockname(pipe->fd, &us.soa, &uslen); + Getsockname(fd, &us.soa, &uslen); Notice1("local address: %s", 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 */ case XIOWRITE_PIPE: + case XIOWRITE_2PIPE: do { - writt = Write(pipe->para.bipipe.fdout, buff, bytes); + writt = Write(fd, buff, bytes); } while (writt < 0 && errno == EINTR); _errno = errno; if (writt < 0) { Error4("write(%d, %p, "F_Zu"): %s", - pipe->para.bipipe.fdout, buff, bytes, strerror(_errno)); + fd, buff, bytes, strerror(_errno)); errno = _errno; return -1; } @@ -136,22 +141,14 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) { } break; - case XIOWRITE_2PIPE: - do { - writt = Write(pipe->para.exec.fdout, buff, bytes); - } while (writt < 0 && errno == EINTR); - _errno = errno; - if (writt < 0) { - Error4("write(%d, %p, "F_Zu"): %s", - pipe->para.exec.fdout, buff, bytes, strerror(_errno)); - errno = _errno; - return -1; - } - if ((size_t)writt < bytes) { - Warn2("write() only processed "F_Zu" of "F_Zu" bytes", - writt, bytes); - } - break; +#if WITH_TEST + case XIOWRITE_TEST: + /* this function prints its own error messages */ + return xiowrite_test(pipe, buff, bytes); + case XIOWRITE_TESTREV: + /* this function prints its own error messages */ + return xiowrite_testrev(pipe, buff, bytes); +#endif /* WITH_TEST */ #if WITH_OPENSSL case XIOWRITE_OPENSSL: