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]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
-u
-U
$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. 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.IP6-SENDTO:<host>:<protocol>
IP-DATAGRAM:<address>:<protocol>
IP4-DATAGRAM:<host>:<protocol>
IP6-DATAGRAM:<host>:<protocol>
IP-RECVFROM:<protocol>
OPEN:<filename>
open()
system call
- (example).
+ Opens <filename> using the open()
system call.
This operation fails on UNIX domain sockets. PTY
PTY:<symlink>
READLINE
TCP4:<host>:<port>
TCP6:<host>:<port>
TCP4-LISTEN:<port>
TCP6-LISTEN:<port>
TUN:<if-addr>/<bits>
/dev/net/tun
.
- UDP:<host>:<port>
UDP:<host>:<port>
UDP6:<host>:<port>
UDP-DATAGRAM:<address>:<port>
UDP4-DATAGRAM:<address>:<port>
UDP6-DATAGRAM:<address>:<port>
UDP-LISTEN:<port>
UDP-LISTEN:<port>
UDP-SENDTO:<host>:<port>
UDP-SENDTO:<host>:<port>
UDP4-SENDTO:<host>:<port>
UDP6-SENDTO:<host>:<port>
UDP-RECVFROM:<port>
UNIX-CLIENT:<filename>
UNIX:<filename>
ABSTRACT-CONNECT:<string>
ABSTRACT-LISTEN:<string>
ABSTRACT-SENDTO:<string>
ABSTRACT-RECVFROM:<string>
ABSTRACT-RECV:<string>
ABSTRACT-CLIENT:<string>
setlk
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.
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".
-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.
-
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.
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.
-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(":