added inter address exec and system modules

This commit is contained in:
Gerhard Rieger 2009-04-03 11:30:01 +02:00
parent b53a9afba7
commit 515c305a7f
52 changed files with 2887 additions and 1844 deletions

View file

@ -1,5 +1,5 @@
# source: Makefile.in # source: Makefile.in
# Copyright Gerhard Rieger 2001-2008 # Copyright Gerhard Rieger 2001-2009
# Published under the GNU General Public License V.2, see file COPYING # Published under the GNU General Public License V.2, see file COPYING
# note: @...@ forms are filled in by configure script # note: @...@ forms are filled in by configure script
@ -73,10 +73,17 @@ HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.
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 xiosigchld.h xiostatic.h xio-nop.h xio-test.h
DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT doc/socat.yo 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 doc/socat-genericsocket.html DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY \
DEVELOPMENT doc/socat.yo 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 doc/socat-genericsocket.html \
doc/socat-addresschain.html doc/socat-exec.html
SHFILES = daemon.sh mail.sh ftp.sh readline.sh SHFILES = daemon.sh mail.sh ftp.sh readline.sh
TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \ TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \
proxy.sh socks4a-echo.sh testcert.conf proxy.sh socks4a-echo.sh bin/cat2.sh bin/predialog.sh \
bin/cat2.sh bin/predialog.sh \
testcert.conf
OSFILES = Config/Makefile.Linux-2-6-24 Config/config.Linux-2-6-24.h \ OSFILES = Config/Makefile.Linux-2-6-24 Config/config.Linux-2-6-24.h \
Config/Makefile.SunOS-5-10 Config/config.SunOS-5-10.h \ Config/Makefile.SunOS-5-10 Config/config.SunOS-5-10.h \
Config/Makefile.FreeBSD-6-1 Config/config.FreeBSD-6-1.h \ Config/Makefile.FreeBSD-6-1 Config/config.FreeBSD-6-1.h \

View file

@ -1 +1 @@
"2.0.0-b2" "2+exec"

68
bin/cat2.sh Executable file
View file

@ -0,0 +1,68 @@
#! /bin/bash
# source: cat2.sh
# Copyright Gerhard Rieger 2009
# Published under the GNU General Public License V.2, see file COPYING
# This is an example script that shows how to write a script for use with socat
# intermediate addresses. it shows a simple case consisting of two
# unidirectional programs.
# note how the n>&- and n<&- controls are used to close FDs on sub processes
# to make half close possible.
# uncomment this if you want to analyse which file descriptors are open
#filan -s -o+2; sleep 1; echo
# these are the "right side" file descriptors provided by socat; 0 and 1 are
# the "left side" FDs
RINFD=3
ROUTFD=4
if true; then
# this is a typical example.
#these work fine
socat -u - - <&3 3<&- 4>&- & # right (3) to left (1)
socat -u - - <&0 >&4 4>&- 3<&- & # left (0) to right (4)
#strace -o /tmp/cat.strace -v -tt -f -F -x -s 1024 cat <&3 3<&- 4>&- & # right (3) to left (1)
#cat <&0 1>&- >&4 4>&- 3<&- & # left (0) to right (4)
exec 1>&- 4>&-
exec 0<&- 3<&-
elif false; then
# works except close in reverse direction
cat <&3 3<&- 4>&- & # right (3) to left (1)
exec cat <&0 1>&- >&4 4>&- 3<&- # left (0) to right (4)
elif true; then
# works - forw, rev
#socat $SOCAT_OPTS -u fd:$RINFD - </dev/null 4>&- & # right to left
#socat $SOCAT_OPTS -u - fd:$ROUTFD >/dev/null 3<&- & # left to right
exec 1>&- 4>&-
exec 0<&- 3<&-
elif false; then
# works - forw, rev
socat -u - - <&3 3<&- 4>&- & # right (3) to left (1)
exec socat -u - - <&0 1>&- >&4 4>&- 3<&- # left (0) to right (4)
else
# works except close in reverse
#filan -s -o+2 <&3 3<&- 4>&- & # right (3) to left (1)
cat <&3 3<&- 4>&- & # right (3) to left (1)
#socat -d -d -d -d -u - - <&3 3<&- 4>&- & # right (3) to left (1)
#sleep 1; echo >&2; filan -s -o+2 <&0 >&4 4>&- 3<&- & # left (0) to right (4)
#cat <&0 >&4 4>&- 3<&- & # left (0) to right (4)
socat -u - - <&0 >&4 4>&- 3<&- & # left (0) to right (4)
exec 1>&- 4>&-
exec 0<&- 3<&-
#sleep 1; echo >&2; filan -s -o+2
fi
wait

53
bin/predialog.sh Executable file
View file

@ -0,0 +1,53 @@
#! /bin/bash
# source: predialog.sh
# Copyright Gerhard Rieger 2009
# Published under the GNU General Public License V.2, see file COPYING
# This is an example script that shows how to write a script for use with socat
# intermediate addresses. it shows a case where an initial dialog on the right
# side is performed. afterwards data is just passed in both directions.
# uncomment this if you want to analyse which file descriptors are open
#filan -s -o+2; sleep 1; echo
# these are the "right side" file descriptors provided by socat; 0 and 1 are
# the "left side" FDs
RINFD=3
ROUTFD=4
verbose=
# parse options
SPACES=" "
while [ -n "$1" ]; do
case "$1" in
-v) verbose=1 ;;
*) echo "$0: unknown option \"$1\"" >&2; exit -1 ;;
esac
shift
done
msg () {
[ "$verbose" ] && echo "$0: $1" >&2
}
# send a request
msg "sending request"
echo -e "CONNECT 10.0.0.1:80 HTTP/1.0\n" >&4
# read reply
msg "waiting for reply"
read -r <&3
case "$REPLY" in
"HTTP/1.0 200 OK") ;;
*) msg "bad reply \"$REPLY\"" exit 1 ;;
esac
# skip headers until empty line
msg "skipping reply headers"
while read -r <&3 && ! [ "$REPLY" = "" ]; do :; done
wait
msg "starting data transfer"
# now just pass traffic in both directions
#SOCAT_OPTS="-lu -d -d -d -d"
exec socat $SOCAT_OPTS - "fd:$ROUTFD:$RINFD"

320
doc/socat-addresschain.html Normal file
View file

@ -0,0 +1,320 @@
<!-- source: socat-exec.html -->
<!-- Copyright Gerhard Rieger 2009 -->
<html><head>
<title>Socat address chains</title>
<link rel="stylesheet" type="text/css" href="dest-unreach.css">
</head>
<body>
<h1>Socat address chains</h1>
<a name="introduction"/>
<h2>Introduction</h2>
<p>Socat version 2 can concatenate multiple modules and transfer data between
them bidirectionally.
<p>
<a name="example1"/>
<h2>Example 1: OpenSSL via HTTP proxy</h2>
<span class="frame"><span class="shell">
socat - "OPENSSL,verify=0 | PROXY:secure.domain.com:443 | TCP:proxy.domain.com:8080"
</span></span>
<p>This command does the following: socat connects to proxy.domain.com on port
8080 and sends a proxy CONNECT request for secure.domain.com port 443; this is
similar to the proxy address available in version 1. Once the proxy server
acknowledges successful
connection to the target (SSL) server, socat starts SSL negotiation and then
transfers data between its stdio and the SSL server.
</p>
<a name="basics"/>
<h2>Address chain basics</h2>
<p>socat version 1 was able to open two addresses and transfer data between
them. "Addresses" could be just sockets or other file descriptors, or could
be a little more complex like proxy client or OpenSSL server and client. It
was, though desirable, practically not possible to combine complex address
types, or to use other socket types than the predefined ones (usually TCP)
with complex addresses.
</p>
<p>socat version 2 has been designed to overcome these limitations. First, the
complex address types are now separated from the underlying file descriptor
types. Second, complex addresses that are now called <em>inter addresses</em>
can be concatenated to an <em>address chain</em>; however, an <em>endpoint
address</em> that just provides file descriptors must be the last component
of an address chain.
</p>
<p>The socat invocation takes two address chains, opens them, and transfers
data between them.
</p>
<p>An address chain consists of zero or more inter addresses and one endpoint
address, all separated by the pipe character '|'. When starting socat from
the command line these characters and the optional spaces must be protected
from the shell; it is recommended to put each address chain under double
quotes.
</p>
<p>The (bidirectional) inter addresses that are available with a socat
implementation can be listed with the following command:
</p>
<span class="frame"><span class="shell">
socat -h |egrep 'b ..b groups='</span></span>
<p>A full socat 2.0.0-b3 program provides the following inter addresses:
</p>
<table border=1>
<tr><th>name</th><th>description</th></tr>
<tr><td>NOP</td><td>transfers data unmodified</td></tr>
<tr><td>OPENSSL-CLIENT</td><td>performs OpenSSL client negotiation, then
encrypts/decrypts data</td></tr>
<tr><td>OPENSSL-SERVER</td><td>performs OpenSSL server negotiation, then
encrypts/decrypts data </td></tr>
<tr><td>PROXY</td><td>performs proxy CONNECT client negotiation, then
transfers data unmodified</td></tr>
<tr><td>SOCKS4</td><td>performs socks 4 client negotiation, then
transfers data unmodified</td></tr>
<tr><td>SOCKS4A</td><td>performs socks 4a client negotiation, then
transfers data unmodified</td></tr>
<tr><td>SOCKS5</td><td>performs socks 5 TCP client negotiation, then
transfers data unmodified</td></tr>
<tr><td>TEST</td><td>appends &gt; to forward, and &lt; to reversely
transferred blocks</td></tr>
<tr><td>EXEC</td><td>invokes a program
(see <a href="socat-exec.html">socat-exec.html</a>), then transfers data unmodified</td></tr>
<tr><td>SYSTEM</td><td>invokes the shell (see <a href="socat-exec.html">socat-exec.html</a>), then transfers data unmodified</td></tr>
</table>
<a name="reverse"/>
<h2>Reverse address use</h2>
<p>Inter addresses have two interfaces. In most cases one of
these can be seen as a <em>data</em> interface, where arbitrary data
traffic may occur, and the other as <em>protocol</em> interface where the
transferred data has to follow some rules like socks and HTTP protocol, or
valid encryption.
</p>
<p>Bidirectional inter addresses are usually implemented such that their data
interface is on the "left" side, and the protocol interface on the "right"
side.
</p>
<p>It may be convenient to build an address chain where one or more inter
addresses work in the reverse direction, so their protocol side is connected
to left neighbor in the chain using the protocol, and the data side is
connected to the right neighbor for raw data transfer. socat allows to use
inter addresses in <em>reverse</em> direction by preceding their keyword with
&circ;.
</p>
<a name="example2"/>
<h2>Example 2:</h2>
<p>Endpoint addresses that fork should usually build the first socat address
chain, without inter addresses. For creating an SSL to TCP gateway that
handles multiple connections the following command line does the job:
</p>
<span class="frame"><span class="shell">
socat TCP-LISTEN:443,reuseaddr,fork "^OPENSSL-SERVER,cert=server.pem | TCP:somehost:80"
</span></span>
<p>Without the reverse usage of the SSL server address, socat would "speak"
clear text with the clients that connected to its left address, and SSL to
somehost.
</p>
<a name="unidirectional"/>
<h2>Unidirectional data transfer</h2>
<p>Like in socat version 1, it is possible to specify unidirectional transfers
with version 2. Use socat options <a href="socat.html#OPTION_u">-u</a> or
<a href="socat.html#OPTION_U">-U</a>.
</p>
<p>Unidirectional transfer must be supported by the involved inter addresses;
e.g., SSL requires a bidirectional channel for negotiation of encryption
parameters etc.
</p>
<p>It is possible to mix uni- and bidirectional transfers within one address
chain: Think of a simple file transfer over SSL.
</p>
<p>The socat help function can tell us which address types support which kinds
of transfer:</p>
<span class="frame"><span class="shell">
socat -h |egrep 'openssl-server'</span></span>
<p>gives the following output:
</p>
<p><pre> openssl-server rwb b groups=CHILD,RETRY,OPENSSL
openssl-server:&lt;port&gt; rwb groups=FD,SOCKET,LISTEN,CHILD,RETRY,RANGE,IP4,IP6,TCP,OPENSSL</pre>
</p>
<p>The <tt>rwb &nbsp; b</tt> flags mean that this address type can handle readonly,
writeonly, and bidirectional transfers on its left (data) side, but only
bidirectional on its right (protocol) side.
</p>
<p>The second line describes the (version 1) endpoint form: no right side
traffic kinds are specified because this address type establishes its protocol
communication itself.
</p>
<a name="dual"/>
<h2>Dual inter addresses</h2>
<p>In socat version 1 it was already possible to combine two unidirectional
addresses to one bidrectional address. This idea has been extended in version
2: Two unidirectional inter addresses can be combined to one bidirectional
transfer unit.
</p>
<p><em>Note: in version 1, the dual specification was like
</em><tt>righttoleft!!lefttoright</tt><em>. In version 2, it is:
</em><tt>lefttoright%righttoleft</tt><em>. This is the only major incompatibility
between versions 1 and 2.</em>
</p>
<p>With the few already available inter address types, this feature has no
practical use except with <a href="socat-exec.html">exec and system</a> type
addresses. However, the general function shall be described using the
hypothetical inter address types <tt>gzip</tt> and <tt>gunzip</tt>.
</p>
<p>Let us design these inter address types: <tt>gzip</tt> is a module that
reads arbitrary data on its left ("data") side, compresses it, and writes the
compressed data to its right (protocol side) neighbor.
<!-- Data that arrives onits right side is uncompressed and passed to the
left neighbor. -->
</p>
<p><tt>gunzip</tt> reads gzip compressed data on its left side and writes the
raw uncompressed data on its right side.
</p>
<p>socat can combine these to provide a bidirectional compress/decompress
function:<br>
<tt>gzip%gunzip</tt>
</p>
<p>Data coming from the left is passed through gzip and sent to the right;
data coming from the right is passed through gunzip and sent to the left.
</p>
<p>When the reverse functionality is desired this arrangement does the job:<br>
<tt>gunzip%gzip</tt>
</p>
<a name="fork"/>
<h2>fork</h2>
<p>socat provides the <tt>fork</tt> address option for uses like network
servers where multiple clients can connect and are handled in parallel in
different socat sub processes.
</p>
<p>When the sub processes should work independently (share no socat file
descriptors) the fork option must be applied to the last component of the
first address chain. For better readability it is advisable to have only the
"left" endpoint address in the left chain and put all intermediate addresses
into the right chain.
</p>
<a name="understanding"/>
<h2>Understanding chain implementation</h2>
<p>The idea of concatenated modules in socat is not new. But a few attempts to
completely rewrite and enhance the socat transfer engine
were never completed. At last, it was decided to choose an approach that
requires only moderate changes to socats transfer engine and the existing
address types.
</p>
<p>Think of several socat1 like processes somehow combined - with an abstract
operator || :
</p>
<span class="frame"><span class="shell">
socat - openssl || socat - proxy:secure.domain.com || socat - tcp:proxy.domain.com:8080
</span></span>
<p>The solution was to put all these into one process but have each socat engine
run in its own thread. The transfer between the engines goes over socket
pairs, so the engines see file descriptors as usual. The main work then was
to implement the functionality for opening address chains which includes
parsing, creating socket pairs and threads, combining the addresses, taking
care of unidirectional, dual, and reverse addresses etc.
</p>
<p>Here is the socat version 2 command line of example 1:<br>
<tt>socat - "OPENSSL,verify=0 | PROXY:secure.domain.com:443 | TCP:proxy.domain.com:8080"</tt>
<p>A schematic representation of how this is realized in socat:<br>
<tt>STDIO - engine[thread 0] - OPENSSL - socket pair - (FD) - engine[thread 1]
- PROXY - socket pair - (FD) - engine[thread 2] - TCP</tt>
</p>
<p>where FD means a trivial address similar to the FD (file descriptor) address
type.
</p>
<p>For debugging address chains it proved useful to write down two lines and to note the actual file descriptor numbers:</p>
<pre> STDIO ^ OPENSSL | ^ PROXY | ^ TCP
0,1 ^ 6 | 7 ^ 4 | 5 ^ 3</pre>
<p>The symbol <b>&circ;</b> means a socat transfer engine.
</p>
<p>Now the implementation of the reverse address feature should be easier to
understand. While a forward address is put to the right side of its
engine, a reverse address is just put to the left side. Example 2 can be
explained so:
</p>
<p>Example 2 command line:<br>
<tt>socat TCP-LISTEN:443,reuseaddr,fork "^OPENSSL-SERVER,cert=server.pem |
TCP:somehost:80"</tt>
</p>
<p>Schematic representation:<br>
<tt>TCP-LISTEN - engine[thread 0] - (FD) - socket pair - OPENSSL-SERVER -
engine[thread 1] - TCP</tt>
</p>
<p>Debug schema:<br>
<pre>
TCP-L ^ | SSL-SERV ^ TCP
3 ^ 5 | 6 ^ 4</pre>
<a name="commtypes"/>
<h2>Communication types</h2>
<p>For communication between the address modules of consecutive transfer
engines socat provides pairs (or quadruples) of file descriptors. You may
think about these as two normal UNIX pipes (fifos), one for left-to-right and
the other for right-to-left data transfer.
</p>
<p>There are a few requirements that these file descriptors should fulfill,
however they are different depending on the libraries used by the inter
address modules (e.g. libopenssl) or by external programs that are involved
(see <a href="socat-exec.html">socat-exec.html</a>).
</p>
<p>The factors to consider for these file dscriptors are:
</p>
<ul>
<li>Half close: when a module terminates communication on its write channel,
its read channel should still stay open.</li>
<li>Half close method: A module might half close a connection
using <tt>close()</tt> or <tt>shutdown()</tt> methods.</li>
<li>Buffering: The output buffering behaviour of some modules can be
influenced by the type of file descriptor</li>
<li>INET: Some external programs require a TCP/IPv4 file descriptor</li>
</ul>
<p>This table lists the available communication types and their
properties:</p>
<table border=1>
<tr><th>comm.type</th><th>half close with close()</th><th>allows shutdown</th><th>avoids buffering</th><th>TCP/IPv4</th></tr>
<tr><td>socketpairs</td><td>OK</td><td>OK</td><td>no</td><td>no</td></tr>
<tr><td>socketpair</td><td>no</td><td>OK</td><td>no</td><td>no</td></tr>
<tr><td>pipes</td><td>OK</td><td>no</td><td>no</td><td>no</td></tr>
<tr><td>ptys</td><td>OK</td><td>no</td><td>yes</td><td>no</td></tr>
<tr><td>tcp</td><td>no</td><td>yes</td><td>no</td><td>yes</td></tr>
</table>
<p>The default is socketpairs.
</p>
<p>The overall communication type can be chosen using the <a href="socat.html#option_c"><tt>-c</tt></a> socat
option. With socat 2.0.0-b3 it is not possible to use different communication
types in one process (exception: right side of exec/system modules)
</p>
<small>Copyright: Gerhard Rieger 2009</small><br>
<small>License: <a href="http://www.fsf.org/licensing/licenses/fdl.html">GNU Free Documentation License (FDL)</a></small>
</p>
</body>
</html>

114
doc/socat-exec.html Normal file
View file

@ -0,0 +1,114 @@
<!-- source: socat-exec.html -->
<!-- Copyright Gerhard Rieger 2009 -->
<html><head>
<title>Executing programs using socat</title>
<link rel="stylesheet" type="text/css" href="dest-unreach.css">
</head>
<body>
<h1>Executing programs using socat</h1>
<h2>Introduction</h2>
<p>From its very beginning socat provided the <tt>EXEC</tt> and <tt>SYSTEM</tt>
address types for executing programs or scripts and exchanging data with
them. Beginning with version 2 - with implementation of the address chain
feature (inter addresses) - these address types were enhanced to allow
execution of programs also in inter address context.
</p>
<h2>Program context types</h2>
<p>Currently socat provides three contexts (interfaces) for program or script
execution:
<ul>
<li>The <em>endpoint</em> context: this is the classical situation where
socat equips the program with stdin and stdout. It does not
matter if the program uses other external communication channels. Address
keywords: EXEC, SYSTEM. This variant should be easy to understand in terms
of socat version 1 functionality and is therefore not further
discussed here.</li>
<li>The <em>bidirectional inter address</em> context: socat expects the
program to use two bidirectional channels: stdin and stdout on its "left"
side and file descriptors 3 and 4 on its "right" side. This allows to
provide nearly arbitrary data manipulations within the context of socat
chains. Address keywords: EXEC, SYSTEM.</li>
<li>The <em>unidirectional inter address</em> context: for easy
integration of standard UNIX programs socat provides the EXEC1 and SYSTEM1
address types where socat provides stdin on the "left" side and stdout on
the "right" side of the program, or vice versa for right-to-left
transfers.</li>
</ul>
</p>
<p>Note: The <em>endpoint</em> and the <em>unidirectional inter address</em>
contexts both just use the program's stdio to communicate with it. However,
in practice the last form will in most cases just manipulate and transfer
data, while the first form will usually have side effects by communicating
with exteral resources or by writing to the file system etc.
</p>
<h2>Executing programs in bidirectional inter address context</h2>
<p>socat address chains concatenate internal modules that communicate
bidirectionally.
For example, a chain that establishes encrypted connection to a socks server
might look something like this (parameters and options dropped):
</p>
<p><code>"SOCKS:... | OPENSSL-CLIENT | TCP:..."</code></p>
<p>If you have a program that implements a new encryption protocol the chain
could be changed to:
</p>
<p><code>"SOCKS:... | EXEC:myencrypt.sh | TCP:..."</code></p>
<p>The complete example:</p>
<p><code>socat - "SOCKS:www.domain.com:80 | EXEC:myencrypt.sh | TCP:encrypt.secure.org:444"</code></p>
<p>The <tt>myencrypt.sh</tt> script would be a wrapper around some myencrypt
program. It must adhere a few rules: It reads and writes cleartext data on
its left side (FDs 0 and 1), and it reads and writes encrypted data on its
right side (FDs 3 and 4). Thus, cleartext data would come from the left on FD
0, be encrypted, and sent to the right side through FD 4. Encrypted data would
come from the the right on FD 3, be unencrypted, and sent to the left side
through FD 1. It does not matter if the encryption protocol would required
negotiations or multiple packets on the right side.
</p>
<p>The <tt>myencrypt.sh</tt> script might log to syslog, its own log
file, or to stderr - this is independend of socat. It might have almost
arbitrary side effects.
</p>
<p>For optimal integration the script should be able to perform half-close and
should be able work with different file descriptor types (sockets, pipes,
ptys).
</p>
<p>The socat source distribution contains two example scripts that focus on
partial aspects:
<ul>
<li><tt>predialog.sh</tt> implements an initial dialog on the "right" script
side and, after successful completion, begins to transfer data unmodified in
both directions.</li>
<li><tt>cat2.sh</tt> shows how to use two programs unidirectionally to gain
bidirectional transfer. The important aspects here are the shell based
input / output redirections that are necessary for half-close.</li>
</ul>
<h2>Using unidirectional inter addresses</h2>
<p>There exist lots of UNIX programs that perform data manipulation like
compression or encoding from stdin to stdout, while related programs perform
the reverse operation (decompression, decoding...) also from stdin to
stdout. socat makes it easy to use those programs directly, i.e. without the
need to write a bidirectional wrapper shell script.
</p>
<p><code>socat - "exec1:gzip % exec1:gunzip | tcp:remotehost:port"</code>
</p>
<p>The % character creates a dual communication context where different
inter addresses are used for left-to-right and right-to-left transer (see
<a href="socat-addresschain.html">socat-addresschain.html#dual</a>. socat
generates stdin/stdout file descriptors for both programs independently.
</p>
<p>
<small>Copyright: Gerhard Rieger 2009</small><br>
<small>License: <a href="http://www.fsf.org/licensing/licenses/fdl.html">GNU Free Documentation License (FDL)</a></small>
</p>
</body>
</html>

View file

@ -10,7 +10,7 @@ def(Filan)(0)(bf(Filan))
def(procan)(0)(bf(procan)) def(procan)(0)(bf(procan))
def(Procan)(0)(bf(Procan)) def(Procan)(0)(bf(Procan))
manpage(socat)(1)(Oct 2008)()() manpage(socat)(1)(Apr 2009)()()
whenhtml( whenhtml(
label(CONTENTS) label(CONTENTS)
@ -38,7 +38,7 @@ manpagename(socat) (Multipurpose relay (SOcket CAT))
label(SYNOPSIS) label(SYNOPSIS)
manpagesynopsis() manpagesynopsis()
tt(socat [options] <address> <address>)nl() tt(socat [options] <address-chain> <address-chain>)nl()
tt(socat -V)nl() tt(socat -V)nl()
tt(socat -h[h[h]] | -?[?[?]])nl() tt(socat -h[h[h]] | -?[?[?]])nl()
tt(filan)nl() tt(filan)nl()
@ -51,9 +51,8 @@ Socat() is a command line based utility that establishes two bidirectional byte
streams and transfers data between them. Because the streams can be constructed streams and transfers data between them. Because the streams can be constructed
from a large set of different types of data sinks and sources from a large set of different types of data sinks and sources
(see link(address types)(ADDRESS_TYPES)), and because lots of (see link(address types)(ADDRESS_TYPES)), and because lots of
link(address options)(ADDRESS_OPTIONS) may be applied to the streams, socat can link(address options)(ADDRESS_OPTIONS) may be applied to the streams, socat() can
be used for many different purposes. be used for many different purposes.
It might be one of the tools that one `has already needed'.
Filan() is a utility that prints information about its active file Filan() is a utility that prints information about its active file
descriptors to stdout. It has been written for debugging socat(), but might be descriptors to stdout. It has been written for debugging socat(), but might be
@ -69,14 +68,14 @@ The life cycle of a socat() instance typically consists of four phases.
In the em(init) phase, the command line options are parsed and logging is In the em(init) phase, the command line options are parsed and logging is
initialized. initialized.
During the em(open) phase, socat() opens the first address and afterwards the During the em(open) phase, socat() opens the first address chain and afterwards
second address. These steps are usually blocking; thus, especially for complex address types like socks, the second address chain. These steps are usually blocking; thus, connection
connection requests or authentication dialogs must be completed before the next requests or authentication dialogs must be completed before the next step is
step is started. started.
In the em(transfer) phase, socat() watches both streams' read and write file In the em(transfer) phase, socat() watches both streams' read and write file
descriptors via code(select()), and, when data is available on one side em(and) descriptors via code(select()), and, when data is available on one side em(and)
can be written to the other side, socat reads it, performs newline can be written to the other side, socat() reads it, performs newline
character conversions if required, and writes the data to the write file character conversions if required, and writes the data to the write file
descriptor of the other stream, then continues waiting for more data in both descriptor of the other stream, then continues waiting for more data in both
directions. directions.
@ -98,7 +97,7 @@ link(address options)(ADDRESS_OPTIONS) that are used as parts of link(address sp
startdit() startdit()
dit(bf(tt(-V))) dit(bf(tt(-V)))
Print version and available feature information to stdout, and exit. Print version and available feature information to stdout, and exit.
dit(bf(tt(-h | -?))) label(option_h)dit(bf(tt(-h | -?)))
Print a help text to stdout describing command line options and available address Print a help text to stdout describing command line options and available address
types, and exit. types, and exit.
dit(bf(tt(-hh | -??))) dit(bf(tt(-hh | -??)))
@ -157,17 +156,17 @@ label(option_s)dit(bf(tt(-s)))
By default, socat() terminates when an error occurred to prevent the process By default, socat() terminates when an error occurred to prevent the process
from running when some option could not be applied. With this from running when some option could not be applied. With this
option, socat() is sloppy with errors and tries to continue. Even with this option, socat() is sloppy with errors and tries to continue. Even with this
option, socat will exit on fatals, and will abort connection attempts when option, socat() will exit on fatals, and will abort connection attempts when
security checks failed. security checks failed.
label(option_t)dit(bf(tt(-t))tt(<timeout>)) label(option_t)dit(bf(tt(-t))tt(<timeout>))
When one channel has reached EOF, the write part of the other channel is shut When one channel has reached EOF, the write part of the other channel is shut
down. Then, socat() waits <timeout> [link(timeval)(TYPE_TIMEVAL)] seconds down. Then, socat() waits <timeout> [link(timeval)(TYPE_TIMEVAL)] seconds
before terminating. Default is 0.5 seconds. This timeout only applies to before terminating. Default is 0.5 seconds. This timeout only applies to
addresses where write and read part can be closed independently. When during addresses where write and read part can be closed independently. When during
the timeout interval the read part gives EOF, socat terminates without the timeout interval the read part gives EOF, socat() terminates without
awaiting the timeout. awaiting the timeout.
label(option_T)dit(bf(tt(-T))tt(<timeout>)) label(option_T)dit(bf(tt(-T))tt(<timeout>))
Total inactivity timeout: when socat is already in the transfer loop and Total inactivity timeout: when socat() is already in the transfer loop and
nothing has happened for <timeout> [link(timeval)(TYPE_TIMEVAL)] seconds nothing has happened for <timeout> [link(timeval)(TYPE_TIMEVAL)] seconds
(no data arrived, no interrupt occurred...) then it terminates. (no data arrived, no interrupt occurred...) then it terminates.
Useful with protocols like UDP that cannot transfer EOF. Useful with protocols like UDP that cannot transfer EOF.
@ -193,36 +192,77 @@ label(option_4)dit(bf(tt(-4)))
label(option_6)dit(bf(tt(-6))) label(option_6)dit(bf(tt(-6)))
Use IP version 6 in case that the addresses do not implicitly or explicitly Use IP version 6 in case that the addresses do not implicitly or explicitly
specify a version. specify a version.
label(option_c)dit(bf(tt(-c<commtype>)))
Specifies the default communication type for inter address data
transfer. Takes a letter that means a communication type as explained
link(here)(TYPE_COMMTYPE):
startdit()
dit(bf(tt(s))) (lower case s) link(socketpair)(TYPE_COMMTYPE_SOCKETPAIR)
dit(bf(tt(S))) (upper case s) link(socketpairs)(TYPE_COMMTYPE_SOCKETPAIRS)
dit(bf(tt(P))) (upper case p) link(pipes)(TYPE_COMMTYPE_PIPES)
dit(bf(tt(t))) (lower case t) link(tcp)(TYPE_COMMTYPE_TCP)
dit(bf(tt(Y))) (upper case y) link(ptys)(TYPE_COMMTYPE_PTYS)
enddit()
enddit() enddit()
label(ADDRESS_SPECIFICATIONS) label(ADDRESS_SPECIFICATIONS)
manpagesection(ADDRESS SPECIFICATIONS) manpagesection(ADDRESS SPECIFICATIONS)
With the address command line arguments, the user gives socat() instructions and From the two em(address chain) command line argument, socat() gets instructions
the necessary information for establishing the byte streams. and the necessary information for establishing the byte streams.
An address specification usually consists of an address type An address chain consists of a sequence of zero or more em(inter addresses) and
keyword, zero or more required address parameters separated by ':' from the keyword and one em(endpoint address), all separated by '|'.
from each
other, and zero or more address options separated by ','.
The keyword specifies the address type (e.g., TCP4, OPEN, EXEC). For some COMMENT(All addresses are either the first in a chain or have a left neighbor.)
keywords there exist synonyms ('-' for STDIO, TCP for TCP4). Keywords are case
insensitive. An endpoint address is always the last in an address chain; it has no right
neighbor. Endpoint addresses correlate to the addresses concept of socat()
version 1.
Inter addresses always have a right neighbor (either another inter address or
an endpoint address). An inter address transfers data between its left neighbor
(or the main socat() transfer engine when it is the first in the chain) and its
right neighbor.
Addresses (address specifications) usually consist of an address type
keyword, zero or more required address parameters separated by ':' from the
keyword and from each other, and zero or more address options separated by ','
from the address parameters and from each other.
The keyword specifies the address type (e.g., TCP4-CONNECT, OPEN, EXEC). For
some keywords there exist alias names (TCP4 for TCP4-CONNECT or '-' for
STDIO). Keywords are case insensitive.
For a few special address types, the keyword may be omitted: For a few special address types, the keyword may be omitted:
Address specifications starting with a number are assumed to be FD (raw file An address specification starting with a number is assumed to be an
descriptor) addresses; link(FD)(ADDRESS_FD) (raw file descriptor) address;
if a '/' is found before the first ':' or ',', GOPEN (generic file open) is if a '/' is found before the first ':' or ',', link(GOPEN)(ADDRESS_GOPEN)
assumed. (generic file open) is assumed.
The required number and type of address parameters depend on the address The required number and types of address parameters depend on the address
type. E.g., TCP4 requires a server specification (name or address), and a port type. E.g., TCP4 requires a server specification (name or address), and a port
specification (number or service name). specification (number or service name).
Some keywords are overloaded with multiple em(address forms) that may differ in
the following properties: Endpoint or inter address; number of
parameters; supported transfer directions on the left side. To see all
address forms available invoke socat with option link(-h)(option_h). The first
set of <tt>rwb</tt> flags describes the transfer directions on the address's
left side (read, write, and bidirectional, as seen by this address). The second
set describes the required direction on the right side; empty means it is an
endpoint address form.
When parsing the addresses within an address chain socat() takes care of the
data transfer directions between consecutive addresses. For the first address
the directions are bidirectional per default, or unidirectional when when
link(option -u)(option_u) or link(-U)(option_U) is used. For the following
addresses, the required directions are derived from the right side directions
of the left neighbor.
Zero or more address options may be given with each address. They influence the Zero or more address options may be given with each address. They influence the
address in some ways. address in some ways.
Options consist of an option keyword or an option keyword and a value, Options consist of an option keyword or an option keyword and a value
separated by '='. Option keywords are case insensitive. separated by '='. Option keywords are case insensitive.
For filtering the options that are useful with an address For filtering the options that are useful with an address
type, each option is member of one option group. For type, each option is member of one option group. For
@ -232,24 +272,25 @@ belonging to one of these address groups may be used (except with link(option -g
label(ADDRESS_DUAL) label(ADDRESS_DUAL)
Address specifications following the above schema are also called em(single) Address specifications following the above schema are also called em(single)
address specifications. address specifications.
Two single addresses can be combined with "!!" to form a em(dual) type Two single addresses can be combined with "%" to form a em(dual) type
address for one channel. Here, the first address is used by socat() for reading address. Here, the first address is used by socat() for transferring data from
data, and the left to right, and the second address from right to left. Of course this
second address for writing data. There is no way to specify an option only once requires bidirectional context, while both single addresses are integrated
for being applied to both single addresses. unidirectionally.
Usually, addresses are opened in read/write label(ADDRESS_REVERSE)
mode. When an address is part of a dual address specification, or when Inter addresses can be used in reverse mode by prefixing them with the
link(option -u)(option_u) or link(-U)(option_U) is used, an address might be character '^' (caret). That means that the right side of the inter address is
used only for reading or for writing. Considering this is important with some connected to its left neighbor and its left side to its right neighbor.<br>
address types. COMMENT(<em>Note: this can introduce ambiguities with the directions on the right side !!!tbd</em><br>)
Addresses within a dual type inter address can also be reverse.
With socat version 1.5.0 and higher, the lexical analysis tries to handle With socat() version 1.5.0 and higher, the lexical analysis tries to handle
quotes and parenthesis meaningfully and allows escaping of special characters. quotes and parenthesis meaningfully and allows escaping of special characters.
If one of the characters ( { [ ' is found, the corresponding closing If one of the characters ( { [ ' is found, the corresponding closing
character - ) } ] ' - is looked for; they may also be nested. Within these character - ) } ] ' - is looked for; they may also be nested. Within these
constructs, socats special characters and strings : , !! are not handled constructs, socat()s special characters and strings ':' ',' '%' are not handled
specially. All those characters and strings can be escaped with \ or within "" specially. All those characters and strings can be escaped with \ or within "".
label(ADDRESS_TYPES) label(ADDRESS_TYPES)
manpagesection(ADDRESS TYPES) manpagesection(ADDRESS TYPES)
@ -276,17 +317,26 @@ label(ADDRESS_CREAT)dit(bf(tt(CREATE:<filename>)))
link(append)(OPTION_APPEND)nl() link(append)(OPTION_APPEND)nl()
See also: link(OPEN)(ADDRESS_OPEN), link(GOPEN)(ADDRESS_GOPEN) See also: link(OPEN)(ADDRESS_OPEN), link(GOPEN)(ADDRESS_GOPEN)
label(ADDRESS_EXEC)dit(bf(tt(EXEC:<command-line>))) label(ADDRESS_EXEC)dit(bf(tt(EXEC:<command-line>)))
Is an alias for link(EXEC2)(ADDRESS_EXEC2)
label(ADDRESS_EXEC1)dit(bf(tt(EXEC1:<command-line>)))
This is a variation of the link(EXEC2)(ADDRESS_EXEC2) address that provides
unidirectional communication within an address chain: socat() connects the
program's stdin to its left neighbor and its stdout to its right neighbor.
label(ADDRESS_EXEC2)dit(bf(tt(EXEC2:<command-line>)))
Forks a sub process that establishes communication with its parent process Forks a sub process that establishes communication with its parent process
and invokes the specified program with code(execvp()). and invokes the specified program with code(execvp()).
link(<command-line>)(TYPE_COMMAND_LINE) is a simple command link(<command-line>)(TYPE_COMMAND_LINE) is a simple command
with arguments separated by single spaces. If the program name with arguments separated by spaces. If the program name
contains a '/', the part after the last '/' is taken as ARGV[0]. If the contains '/', only the part after the last '/' is taken as ARGV[0]. If the
program name is a relative program name is a relative
path, the code(execvp()) semantics for finding the program via path, the code(execvp()) semantics for finding the program via
code($PATH) code($PATH) apply. nl()
apply. After successful program start, socat() writes data to stdin of the This address may be used as an endpoint address where socat() writes data to
process and reads from its stdout using a unixdomain() socket generated by stdin of the process and reads from its stdout using two unixdomain()
code(socketpair()) per default. (link(example)(EXAMPLE_ADDRESS_EXEC)) nl() sockets generated by code(socketpair()) per default
(link(example)(EXAMPLE_ADDRESS_EXEC)), or as an inter address where
socat() connects the program's stdio to its left neighbor and its file
descriptors 3 and 4 to its right neighbor. nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(EXEC)(GROUP_EXEC),link(FORK)(GROUP_FORK),link(TERMIOS)(GROUP_TERMIOS) nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(EXEC)(GROUP_EXEC),link(FORK)(GROUP_FORK),link(TERMIOS)(GROUP_TERMIOS) nl()
Useful options: Useful options:
link(path)(OPTION_PATH), link(path)(OPTION_PATH),
@ -296,11 +346,10 @@ label(ADDRESS_EXEC)dit(bf(tt(EXEC:<command-line>)))
link(su)(OPTION_SUBSTUSER), link(su)(OPTION_SUBSTUSER),
link(su-d)(OPTION_SUBSTUSER_DELAYED), link(su-d)(OPTION_SUBSTUSER_DELAYED),
link(nofork)(OPTION_NOFORK), link(nofork)(OPTION_NOFORK),
link(pty)(OPTION_PTY), link(commtype)(OPTION_COMMTYPE),
link(stderr)(OPTION_STDERR), link(stderr)(OPTION_STDERR),
link(ctty)(OPTION_CTTY), link(ctty)(OPTION_CTTY),
link(setsid)(OPTION_SETSID), link(setsid)(OPTION_SETSID),
link(pipes)(OPTION_PIPES),
link(login)(OPTION_LOGIN), link(login)(OPTION_LOGIN),
link(sigint)(OPTION_SIGINT), link(sigint)(OPTION_SIGINT),
link(sigquit)(OPTION_SIGQUIT)nl() link(sigquit)(OPTION_SIGQUIT)nl()
@ -349,12 +398,12 @@ label(ADDRESS_IP_SENDTO)dit(bf(tt(IP-SENDTO:<host>:<protocol>)))
link(UDP-SENDTO)(ADDRESS_UDP_SENDTO) link(UDP-SENDTO)(ADDRESS_UDP_SENDTO)
link(UNIX-SENDTO)(ADDRESS_UNIX_SENDTO) link(UNIX-SENDTO)(ADDRESS_UNIX_SENDTO)
label(ADDRESS_INTERFACE)dit(bf(tt(INTERFACE:<interface>))) label(ADDRESS_INTERFACE)dit(bf(tt(INTERFACE:<interface>)))
Communicate with a network connected on an interface using raw packets Communicates with a network connected on an interface using raw packets
including link level data. link(<interface>)(TYPE_INTERFACE) is the name of including link level data. link(<interface>)(TYPE_INTERFACE) is the name of
the network interface. Currently only available on Linux. the network interface. Currently only available on Linux.
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET) nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET) nl()
Useful options: Useful options:
link(pf)(OPTION_PROTOCOL_FAMILY) link(pf)(OPTION_PROTOCOL_FAMILY)nl()
link(type)(OPTION_SO_TYPE)nl() link(type)(OPTION_SO_TYPE)nl()
See also: link(ip-recv)(ADDRESS_IP_RECV) See also: link(ip-recv)(ADDRESS_IP_RECV)
label(ADDRESS_IP4_SENDTO)dit(bf(tt(IP4-SENDTO:<host>:<protocol>))) label(ADDRESS_IP4_SENDTO)dit(bf(tt(IP4-SENDTO:<host>:<protocol>)))
@ -436,7 +485,7 @@ label(ADDRESS_IP_RECV)dit(bf(tt(IP-RECV:<protocol>)))
Opens a raw IP socket of link(<protocol>)(TYPE_PROTOCOL). Depending on option link(pf)(OPTION_PROTOCOL_FAMILY), IP procotol version Opens a raw IP socket of link(<protocol>)(TYPE_PROTOCOL). Depending on option link(pf)(OPTION_PROTOCOL_FAMILY), IP procotol version
4 or 6 is used. It receives packets from multiple unspecified peers and merges the data. 4 or 6 is used. It receives packets from multiple unspecified peers and merges the data.
No replies are possible. No replies are possible.
It can be, e.g., addressed by socat IP-SENDTO address peers. It can be, e.g., addressed by socat() IP-SENDTO address peers.
Protocol 255 uses the raw socket with the IP header being part of the Protocol 255 uses the raw socket with the IP header being part of the
data.nl() data.nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(RANGE)(GROUP_RANGE) nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(RANGE)(GROUP_RANGE) nl()
@ -534,13 +583,14 @@ label(ADDRESS_OPENSSL_LISTEN)dit(bf(tt(OPENSSL-LISTEN:<port>)))
label(ADDRESS_NAMED_PIPE)dit(bf(tt(PIPE:<filename>))) label(ADDRESS_NAMED_PIPE)dit(bf(tt(PIPE:<filename>)))
If link(<filename>)(TYPE_FILENAME) already exists, it is opened. If link(<filename>)(TYPE_FILENAME) already exists, it is opened.
If is does not exist, a named pipe is created and opened. Beginning with If is does not exist, a named pipe is created and opened. Beginning with
socat version 1.4.3, the named pipe is removed when the address is closed socat() version 1.4.3, the named pipe is removed when the address is closed
(but see option link(unlink-close)(OPTION_UNLINK_CLOSE)nl() (but see option link(unlink-close)(OPTION_UNLINK_CLOSE)nl()
Note: When a pipe is used for both reading and writing, it works Note: When a pipe is used for both reading and writing, it works
as echo service.nl() as echo service.nl()
Note: When a pipe is used for both reading and writing, and socat tries Note: When a pipe is used for both reading and writing, and socat() tries
to write more bytes than the pipe can buffer (Linux 2.4: 2048 bytes), socat to write more bytes than the pipe can buffer (Linux 2.4: 2048 bytes), socat
might block. Consider using socat option, e.g., code(-b 2048) nl() might block. Consider using socat() option, e.g., link(code(-b
2048))(option_b) nl()
Option groups: link(FD)(GROUP_FD),link(NAMED)(GROUP_NAMED),link(OPEN)(GROUP_OPEN) nl() Option groups: link(FD)(GROUP_FD),link(NAMED)(GROUP_NAMED),link(OPEN)(GROUP_OPEN) nl()
Useful options: Useful options:
link(rdonly)(OPTION_RDONLY), link(rdonly)(OPTION_RDONLY),
@ -554,9 +604,9 @@ label(ADDRESS_UNNAMED_PIPE)dit(bf(tt(PIPE)))
Creates an unnamed pipe and uses it for reading and writing. It works as an Creates an unnamed pipe and uses it for reading and writing. It works as an
echo, because everything written echo, because everything written
to it appeares immediately as read data.nl() to it appeares immediately as read data.nl()
Note: When socat tries to write more bytes than the pipe can queue (Linux Note: When socat() tries to write more bytes than the pipe can queue (Linux
2.4: 2048 bytes), socat might block. Consider, e.g., using 2.4: 2048 bytes), socat() might block. Consider, e.g., using
option code(-b 2048) nl() option link(code(-b 2048))(option_b) nl()
Option groups: link(FD)(GROUP_FD) nl() Option groups: link(FD)(GROUP_FD) nl()
See also: link(named pipe)(ADDRESS_NAMED_PIPE) See also: link(named pipe)(ADDRESS_NAMED_PIPE)
label(ADDRESS_PROXY_CONNECT)dit(bf(tt(PROXY:<proxy>:<hostname>:<port>))) label(ADDRESS_PROXY_CONNECT)dit(bf(tt(PROXY:<proxy>:<hostname>:<port>)))
@ -564,7 +614,7 @@ label(ADDRESS_PROXY_CONNECT)dit(bf(tt(PROXY:<proxy>:<hostname>:<port>)))
depending on address specification, name resolution, or option depending on address specification, name resolution, or option
link(pf)(OPTION_PROTOCOL_FAMILY), and sends a CONNECT link(pf)(OPTION_PROTOCOL_FAMILY), and sends a CONNECT
request for hostname:port. If the proxy grants access and succeeds to request for hostname:port. If the proxy grants access and succeeds to
connect to the target, data transfer between socat and the target can connect to the target, data transfer between socat() and the target can
start. Note that the traffic need not be HTTP but can be an arbitrary start. Note that the traffic need not be HTTP but can be an arbitrary
protocol. nl() protocol. nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(HTTP)(GROUP_HTTP),link(RETRY)(GROUP_RETRY) nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(HTTP)(GROUP_HTTP),link(RETRY)(GROUP_RETRY) nl()
@ -641,7 +691,7 @@ label(ADDRESS_SCTP6_CONNECT)dit(bf(tt(SCTP6-CONNECT:<host>:<port>)))
label(ADDRESS_SCTP_LISTEN)dit(bf(tt(SCTP-LISTEN:<port>))) label(ADDRESS_SCTP_LISTEN)dit(bf(tt(SCTP-LISTEN:<port>)))
Listens on <port> [link(TCP service)(TYPE_TCP_SERVICE)] and accepts a Listens on <port> [link(TCP service)(TYPE_TCP_SERVICE)] and accepts a
TCP/IP connection. The IP version is 4 or the one specified with TCP/IP connection. The IP version is 4 or the one specified with
address option link(pf)(OPTION_PROTOCOL_FAMILY), socat option address option link(pf)(OPTION_PROTOCOL_FAMILY), socat() option
(link(-4)(option_4), link(-6)(option_6)), or environment variable link(SOCAT_DEFAULT_LISTEN_IP)(ENV_SOCAT_DEFAULT_LISTEN_IP). (link(-4)(option_4), link(-6)(option_6)), or environment variable link(SOCAT_DEFAULT_LISTEN_IP)(ENV_SOCAT_DEFAULT_LISTEN_IP).
Note that opening Note that opening
this address usually blocks until a client connects.nl() this address usually blocks until a client connects.nl()
@ -675,14 +725,14 @@ label(ADDRESS_SCTP6_LISTEN)dit(bf(tt(SCTP6-LISTEN:<port>)))
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE),link(IP6)(GROUP_IP6),link(SCTP)(GROUP_SCTP),link(RETRY)(GROUP_RETRY) nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE),link(IP6)(GROUP_IP6),link(SCTP)(GROUP_SCTP),link(RETRY)(GROUP_RETRY) nl()
label(ADDRESS_SOCKET_CONNECT)dit(bf(tt(SOCKET-CONNECT:<domain>:<protocol>:<remote-address>))) label(ADDRESS_SOCKET_CONNECT)dit(bf(tt(SOCKET-CONNECT:<domain>:<protocol>:<remote-address>)))
Creates a stream socket using the first and second given socket parameters Creates a stream socket using the first and second given socket parameters
and tt(SOCK_STREAM) (see man socket(2)) and connects to the remote-address. and tt(SOCK_STREAM) (see man socket\(2)) and connects to the remote-address.
The two socket parameters have to be specified by link(int)(TYPE_INT) The two socket parameters have to be specified by link(int)(TYPE_INT)
numbers. Consult your OS documentation and include files to find the numbers. Consult your OS documentation and include files to find the
appropriate values. The remote-address must be the link(data)(TYPE_DATA) appropriate values. The remote-address must be the link(data)(TYPE_DATA)
representation of a sockaddr structure without sa_family and (BSD) sa_len representation of a sockaddr structure without sa_family and (BSD) sa_len
components.nl() components.nl()
Please note that you can - beyond the options of the specified groups - also Please note that you can - beyond the options of the specified groups - also
use options of higher level protocols when you apply socat option use options of higher level protocols when you apply socat() option
link(-g)(option_g).nl() link(-g)(option_g).nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY)nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY)nl()
Useful options: Useful options:
@ -699,14 +749,14 @@ label(ADDRESS_SOCKET_CONNECT)dit(bf(tt(SOCKET-CONNECT:<domain>:<protocol>:<remot
link(SOCKET-SENDTO)(ADDRESS_SOCKET_SENDTO) link(SOCKET-SENDTO)(ADDRESS_SOCKET_SENDTO)
label(ADDRESS_SOCKET_DATAGRAM)dit(bf(tt(SOCKET-DATAGRAM:<domain>:<type>:<protocol>:<remote-address>))) label(ADDRESS_SOCKET_DATAGRAM)dit(bf(tt(SOCKET-DATAGRAM:<domain>:<type>:<protocol>:<remote-address>)))
Creates a datagram socket using the first three given socket parameters (see Creates a datagram socket using the first three given socket parameters (see
man socket(2)) and sends outgoing data to the remote-address. The three man socket\(2)) and sends outgoing data to the remote-address. The three
socket parameters have to be specified by link(int)(TYPE_INT) socket parameters have to be specified by link(int)(TYPE_INT)
numbers. Consult your OS documentation and include files to find the numbers. Consult your OS documentation and include files to find the
appropriate values. The remote-address must be the link(data)(TYPE_DATA) appropriate values. The remote-address must be the link(data)(TYPE_DATA)
representation of a sockaddr structure without sa_family and (BSD) sa_len representation of a sockaddr structure without sa_family and (BSD) sa_len
components.nl() components.nl()
Please note that you can - beyond the options of the specified groups - also Please note that you can - beyond the options of the specified groups - also
use options of higher level protocols when you apply socat option use options of higher level protocols when you apply socat() option
link(-g)(option_g).nl() link(-g)(option_g).nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(RANGE)(GROUP_RANGE)nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(RANGE)(GROUP_RANGE)nl()
Useful options: Useful options:
@ -724,14 +774,14 @@ label(ADDRESS_SOCKET_DATAGRAM)dit(bf(tt(SOCKET-DATAGRAM:<domain>:<type>:<protoco
link(SOCKET-RECVFROM)(ADDRESS_SOCKET_RECVFROM) link(SOCKET-RECVFROM)(ADDRESS_SOCKET_RECVFROM)
label(ADDRESS_SOCKET_LISTEN)dit(bf(tt(SOCKET-LISTEN:<domain>:<protocol>:<local-address>))) label(ADDRESS_SOCKET_LISTEN)dit(bf(tt(SOCKET-LISTEN:<domain>:<protocol>:<local-address>)))
Creates a stream socket using the first and second given socket parameters Creates a stream socket using the first and second given socket parameters
and tt(SOCK_STREAM) (see man socket(2)) and waits for incoming connections and tt(SOCK_STREAM) (see man socket\(2)) and waits for incoming connections
on local-address. The two socket parameters have to be specified by on local-address. The two socket parameters have to be specified by
link(int)(TYPE_INT) numbers. Consult your OS documentation and include files link(int)(TYPE_INT) numbers. Consult your OS documentation and include files
to find the appropriate values. The local-address must be the to find the appropriate values. The local-address must be the
link(data)(TYPE_DATA) representation of a sockaddr structure without link(data)(TYPE_DATA) representation of a sockaddr structure without
sa_family and (BSD) sa_len components.nl() sa_family and (BSD) sa_len components.nl()
Please note that you can - beyond the options of the specified groups - also Please note that you can - beyond the options of the specified groups - also
use options of higher level protocols when you apply socat option use options of higher level protocols when you apply socat() option
link(-g)(option_g).nl() link(-g)(option_g).nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(RANGE)(GROUP_RANGE),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY)nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(RANGE)(GROUP_RANGE),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY)nl()
Useful options: Useful options:
@ -747,7 +797,7 @@ label(ADDRESS_SOCKET_LISTEN)dit(bf(tt(SOCKET-LISTEN:<domain>:<protocol>:<local-a
link(SOCKET-SENDTO)(ADDRESS_SOCKET_RECVFROM), link(SOCKET-SENDTO)(ADDRESS_SOCKET_RECVFROM),
link(SOCKET-SENDTO)(ADDRESS_SOCKET_RECV) link(SOCKET-SENDTO)(ADDRESS_SOCKET_RECV)
label(ADDRESS_SOCKET_RECV)dit(bf(tt(SOCKET-RECV:<domain>:<type>:<protocol>:<local-address>))) label(ADDRESS_SOCKET_RECV)dit(bf(tt(SOCKET-RECV:<domain>:<type>:<protocol>:<local-address>)))
Creates a socket using the three given socket parameters (see man socket(2)) Creates a socket using the three given socket parameters (see man socket\(2))
and binds it to <local-address>. Receives arriving data. The three and binds it to <local-address>. Receives arriving data. The three
parameters have to be specified by link(int)(TYPE_INT) numbers. Consult your parameters have to be specified by link(int)(TYPE_INT) numbers. Consult your
OS documentation and include files to find the appropriate values. The OS documentation and include files to find the appropriate values. The
@ -768,7 +818,7 @@ label(ADDRESS_SOCKET_RECV)dit(bf(tt(SOCKET-RECV:<domain>:<type>:<protocol>:<loca
link(SOCKET-SENDTO)(ADDRESS_SOCKET_SENDTO), link(SOCKET-SENDTO)(ADDRESS_SOCKET_SENDTO),
link(SOCKET-RECVFROM)(ADDRESS_SOCKET_RECVFROM) link(SOCKET-RECVFROM)(ADDRESS_SOCKET_RECVFROM)
label(ADDRESS_SOCKET_RECVFROM)dit(bf(tt(SOCKET-RECVFROM:<domain>:<type>:<protocol>:<local-address>))) label(ADDRESS_SOCKET_RECVFROM)dit(bf(tt(SOCKET-RECVFROM:<domain>:<type>:<protocol>:<local-address>)))
Creates a socket using the three given socket parameters (see man socket(2)) Creates a socket using the three given socket parameters (see man socket\(2))
and binds it to <local-address>. Receives arriving data and sends replies and binds it to <local-address>. Receives arriving data and sends replies
back to the sender. The first three parameters have to be specified as back to the sender. The first three parameters have to be specified as
link(int)(TYPE_INT) numbers. Consult your OS documentation and include files link(int)(TYPE_INT) numbers. Consult your OS documentation and include files
@ -792,7 +842,7 @@ label(ADDRESS_SOCKET_RECVFROM)dit(bf(tt(SOCKET-RECVFROM:<domain>:<type>:<protoco
link(SOCKET-RECV)(ADDRESS_SOCKET_RECV) link(SOCKET-RECV)(ADDRESS_SOCKET_RECV)
label(ADDRESS_SOCKET_SENDTO)dit(bf(tt(SOCKET-SENDTO:<domain>:<type>:<protocol>:<remote-address>))) label(ADDRESS_SOCKET_SENDTO)dit(bf(tt(SOCKET-SENDTO:<domain>:<type>:<protocol>:<remote-address>)))
Creates a socket using the three given socket parameters (see man Creates a socket using the three given socket parameters (see man
socket(2)). Sends outgoing data to the given address and receives replies. socket\(2)). Sends outgoing data to the given address and receives replies.
The three parameters have to be specified as link(int)(TYPE_INT) The three parameters have to be specified as link(int)(TYPE_INT)
numbers. Consult your OS documentation and include files to find the numbers. Consult your OS documentation and include files to find the
appropriate values. The remote-address must be the link(data)(TYPE_DATA) appropriate values. The remote-address must be the link(data)(TYPE_DATA)
@ -853,14 +903,28 @@ label(ADDRESS_STDOUT)dit(bf(tt(STDOUT)))
Uses file descriptor 1.nl() Uses file descriptor 1.nl()
Option groups: link(FD)(GROUP_FD) (link(TERMIOS)(GROUP_TERMIOS),link(REG)(GROUP_REG),link(SOCKET)(GROUP_SOCKET)) nl() Option groups: link(FD)(GROUP_FD) (link(TERMIOS)(GROUP_TERMIOS),link(REG)(GROUP_REG),link(SOCKET)(GROUP_SOCKET)) nl()
See also: link(FD)(ADDRESS_FD) See also: link(FD)(ADDRESS_FD)
label(ADDRESS_SYSTEM)dit(bf(tt(SYSTEM:<shell-command>))) label(ADDRESS_SYSTEM)dit(bf(tt(SYSTEM:<command-line>)))
Is an alias for link(SYSTEM2)(ADDRESS_SYSTEM2)
label(ADDRESS_SYSTEM1)dit(bf(tt(SYSTEM1:<command-line>)))
This is a variation of the link(SYSTEM2)(ADDRESS_SYSTEM2) address that provides
unidirectional communication within an address chain: socat() connects the
program's stdin to its left neighbor and its stdout to its right neighbor.
nl()
See also: link(EXEC1)(ADDRESS_EXEC1)
label(ADDRESS_SYSTEM2)dit(bf(tt(SYSTEM2:<shell-command>)))
Forks a sub process that establishes communication with its parent process Forks a sub process that establishes communication with its parent process
and invokes the specified program with code(system()). Please note that and invokes the specified program with code(system()). Please note that
<shell-command> [link(string)(TYPE_STRING)] must <shell-command> [link(string)(TYPE_STRING)] must
not contain ',' or "!!", and that shell meta characters may have to be not contain unprotected ',' or "%", and that shell meta characters may have
protected. to be escaped.
After successful program start, socat() writes data to stdin of the After successful program start, socat() writes data to stdin of the
process and reads from its stdout.nl() process and reads from its stdout.
This address may be used as an endpoint address where socat() writes data to
stdin of the process and reads from its stdout using two unixdomain()
sockets generated by code(socketpair()) per default
(link(example)(EXAMPLE_ADDRESS_EXEC)), or as an inter address where
socat() connects the program's stdio to its left neighbor and its file
descriptors 3 and 4 to its right neighbor. nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(EXEC)(GROUP_EXEC),link(FORK)(GROUP_FORK),link(TERMIOS)(GROUP_TERMIOS) nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(EXEC)(GROUP_EXEC),link(FORK)(GROUP_FORK),link(TERMIOS)(GROUP_TERMIOS) nl()
Useful options: Useful options:
link(path)(OPTION_PATH), link(path)(OPTION_PATH),
@ -870,11 +934,10 @@ label(ADDRESS_SYSTEM)dit(bf(tt(SYSTEM:<shell-command>)))
link(su)(OPTION_SUBSTUSER), link(su)(OPTION_SUBSTUSER),
link(su-d)(OPTION_SUBSTUSER_DELAYED), link(su-d)(OPTION_SUBSTUSER_DELAYED),
link(nofork)(OPTION_NOFORK), link(nofork)(OPTION_NOFORK),
link(pty)(OPTION_PTY), link(commtype)(OPTION_COMMTYPE),
link(stderr)(OPTION_STDERR), link(stderr)(OPTION_STDERR),
link(ctty)(OPTION_CTTY), link(ctty)(OPTION_CTTY),
link(setsid)(OPTION_SETSID), link(setsid)(OPTION_SETSID),
link(pipes)(OPTION_PIPES),
link(sigint)(OPTION_SIGINT), link(sigint)(OPTION_SIGINT),
link(sigquit)(OPTION_SIGQUIT)nl() link(sigquit)(OPTION_SIGQUIT)nl()
See also: link(EXEC)(ADDRESS_EXEC) See also: link(EXEC)(ADDRESS_EXEC)
@ -913,7 +976,7 @@ label(ADDRESS_TCP6_CONNECT)dit(bf(tt(TCP6:<host>:<port>)))
label(ADDRESS_TCP_LISTEN)dit(bf(tt(TCP-LISTEN:<port>))) label(ADDRESS_TCP_LISTEN)dit(bf(tt(TCP-LISTEN:<port>)))
Listens on <port> [link(TCP service)(TYPE_TCP_SERVICE)] and accepts a Listens on <port> [link(TCP service)(TYPE_TCP_SERVICE)] and accepts a
TCP/IP connection. The IP version is 4 or the one specified with TCP/IP connection. The IP version is 4 or the one specified with
address option link(pf)(OPTION_PROTOCOL_FAMILY), socat option address option link(pf)(OPTION_PROTOCOL_FAMILY), socat() option
(link(-4)(option_4), link(-6)(option_6)), or environment variable link(SOCAT_DEFAULT_LISTEN_IP)(ENV_SOCAT_DEFAULT_LISTEN_IP). (link(-4)(option_4), link(-6)(option_6)), or environment variable link(SOCAT_DEFAULT_LISTEN_IP)(ENV_SOCAT_DEFAULT_LISTEN_IP).
Note that opening Note that opening
this address usually blocks until a client connects.nl() this address usually blocks until a client connects.nl()
@ -952,7 +1015,7 @@ label(ADDRESS_TCP6_LISTEN)dit(bf(tt(TCP6-LISTEN:<port>)))
label(ADDRESS_TUN)dit(bf(tt(TUN:<if-addr>/<bits>))) label(ADDRESS_TUN)dit(bf(tt(TUN:<if-addr>/<bits>)))
Creates a Linux TUN/TAP device and assignes to it the address and netmask Creates a Linux TUN/TAP device and assignes to it the address and netmask
defined by the parameters. The resulting network interface is ready for use defined by the parameters. The resulting network interface is ready for use
by other processes; socat serves its "wire side". This address requires read by other processes; socat() serves its "wire side". This address requires read
and write access to the tunnel cloning device, usually code(/dev/net/tun). and write access to the tunnel cloning device, usually code(/dev/net/tun).
nl() nl()
Option groups: link(FD)(GROUP_FD),link(NAMED)(GROUP_NAMED),link(OPEN)(GROUP_OPEN),link(TUN)(GROUP_TUN) nl() Option groups: link(FD)(GROUP_FD),link(NAMED)(GROUP_NAMED),link(OPEN)(GROUP_OPEN),link(TUN)(GROUP_TUN) nl()
@ -1070,7 +1133,7 @@ label(ADDRESS_UDP_SENDTO)dit(bf(tt(UDP-SENDTO:<host>:<port>)))
link(pf)(OPTION_PROTOCOL_FAMILY). It sends packets to and receives packets link(pf)(OPTION_PROTOCOL_FAMILY). It sends packets to and receives packets
from that peer socket only. from that peer socket only.
This address effectively implements a datagram client. This address effectively implements a datagram client.
It works well with socat UDP-RECVFROM and UDP-RECV address peers.nl() It works well with socat() UDP-RECVFROM and UDP-RECV address peers.nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6) nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6) nl()
Useful options: Useful options:
link(ttl)(OPTION_TTL), link(ttl)(OPTION_TTL),
@ -1104,7 +1167,7 @@ label(ADDRESS_UDP_RECVFROM)dit(bf(tt(UDP-RECVFROM:<port>)))
option option
where each arriving packet - from arbitrary peers - is handled by its own sub where each arriving packet - from arbitrary peers - is handled by its own sub
process. This allows a behaviour similar to typical UDP based servers like ntpd process. This allows a behaviour similar to typical UDP based servers like ntpd
or named. This address works well with socat SENDTO address peers.nl() or named. This address works well with socat() SENDTO address peers.nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE) nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE) nl()
Useful options: Useful options:
link(fork)(OPTION_FORK), link(fork)(OPTION_FORK),
@ -1133,7 +1196,7 @@ label(ADDRESS_UDP_RECV)dit(bf(tt(UDP-RECV:<port>)))
Creates a UDP socket on <port> [link(UDP service)(TYPE_UDP_SERVICE)] using UDP/IP version 4 or 6 Creates a UDP socket on <port> [link(UDP service)(TYPE_UDP_SERVICE)] using UDP/IP version 4 or 6
depending on option link(pf)(OPTION_PROTOCOL_FAMILY). depending on option link(pf)(OPTION_PROTOCOL_FAMILY).
It receives packets from multiple unspecified peers and merges the data. It receives packets from multiple unspecified peers and merges the data.
No replies are possible. It works well with, e.g., socat UDP-SENDTO address peers; it behaves similar to a syslog server.nl() No replies are possible. It works well with, e.g., socat() UDP-SENDTO address peers; it behaves similar to a syslog server.nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(RANGE)(GROUP_RANGE) nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(RANGE)(GROUP_RANGE) nl()
Useful options: Useful options:
link(fork)(OPTION_FORK), link(fork)(OPTION_FORK),
@ -1182,7 +1245,7 @@ label(ADDRESS_UNIX_LISTEN)dit(bf(tt(UNIX-LISTEN:<filename>)))
If <filename> exists and is a unixdomain() socket, binding to the address If <filename> exists and is a unixdomain() socket, binding to the address
fails (use option link(unlink-early)(OPTION_UNLINK_EARLY)!). fails (use option link(unlink-early)(OPTION_UNLINK_EARLY)!).
Note that opening this address usually blocks until a client connects. Note that opening this address usually blocks until a client connects.
Beginning with socat version 1.4.3, the file system entry is removed when Beginning with socat() version 1.4.3, the file system entry is removed when
this address is closed (but see option link(unlink-close)(OPTION_UNLINK_CLOSE)) (link(example)(EXAMPLE_ADDRESS_UNIX_LISTEN)).nl() this address is closed (but see option link(unlink-close)(OPTION_UNLINK_CLOSE)) (link(example)(EXAMPLE_ADDRESS_UNIX_LISTEN)).nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET), Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),
link(NAMED)(GROUP_NAMED),link(LISTEN)(GROUP_LISTEN), link(NAMED)(GROUP_NAMED),link(LISTEN)(GROUP_LISTEN),
@ -1204,7 +1267,7 @@ label(ADDRESS_UNIX_LISTEN)dit(bf(tt(UNIX-LISTEN:<filename>)))
label(ADDRESS_UNIX_SENDTO)dit(bf(tt(UNIX-SENDTO:<filename>))) label(ADDRESS_UNIX_SENDTO)dit(bf(tt(UNIX-SENDTO:<filename>)))
Communicates with the specified peer socket, defined by [link(<filename>)(TYPE_FILENAME)] assuming it is a unixdomain() datagram socket. Communicates with the specified peer socket, defined by [link(<filename>)(TYPE_FILENAME)] assuming it is a unixdomain() datagram socket.
It sends packets to and receives packets from that peer socket only. It sends packets to and receives packets from that peer socket only.
It works well with socat UNIX-RECVFROM and UNIX-RECV address peers.nl() It works well with socat() UNIX-RECVFROM and UNIX-RECV address peers.nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET), Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),
link(NAMED)(GROUP_NAMED),link(UNIX)(GROUP_SOCK_UNIX)nl() link(NAMED)(GROUP_NAMED),link(UNIX)(GROUP_SOCK_UNIX)nl()
Useful options: Useful options:
@ -1220,7 +1283,7 @@ label(ADDRESS_UNIX_RECVFROM)dit(bf(tt(UNIX-RECVFROM:<filename>)))
Creates a unixdomain() datagram socket [link(<filename>)(TYPE_FILENAME)]. Creates a unixdomain() datagram socket [link(<filename>)(TYPE_FILENAME)].
Receives one packet and may send one or more answer packets to that peer. Receives one packet and may send one or more answer packets to that peer.
This mode is particularly useful with fork option where each arriving packet - from arbitrary peers - is handled by its own sub process. This mode is particularly useful with fork option where each arriving packet - from arbitrary peers - is handled by its own sub process.
This address works well with socat UNIX-SENDTO address peers.nl() This address works well with socat() UNIX-SENDTO address peers.nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET), Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),
link(NAMED)(GROUP_NAMED),link(CHILD)(GROUP_CHILD), link(NAMED)(GROUP_NAMED),link(CHILD)(GROUP_CHILD),
link(UNIX)(GROUP_SOCK_UNIX) nl() link(UNIX)(GROUP_SOCK_UNIX) nl()
@ -1236,7 +1299,7 @@ label(ADDRESS_UNIX_RECVFROM)dit(bf(tt(UNIX-RECVFROM:<filename>)))
label(ADDRESS_UNIX_RECV)dit(bf(tt(UNIX-RECV:<filename>))) label(ADDRESS_UNIX_RECV)dit(bf(tt(UNIX-RECV:<filename>)))
Creates a unixdomain() datagram socket [link(<filename>)(TYPE_FILENAME)]. Creates a unixdomain() datagram socket [link(<filename>)(TYPE_FILENAME)].
Receives packets from multiple unspecified peers and merges the data. Receives packets from multiple unspecified peers and merges the data.
No replies are possible. It can be, e.g., addressed by socat UNIX-SENDTO address peers. No replies are possible. It can be, e.g., addressed by socat() UNIX-SENDTO address peers.
It behaves similar to a syslog server. It behaves similar to a syslog server.
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET), Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),
link(NAMED)(GROUP_NAMED),link(UNIX)(GROUP_SOCK_UNIX) nl() link(NAMED)(GROUP_NAMED),link(UNIX)(GROUP_SOCK_UNIX) nl()
@ -1467,7 +1530,7 @@ label(OPTION_COOL_WRITE)dit(bf(tt(cool-write)))
Takes it easy when write fails with EPIPE or ECONNRESET and logs the message Takes it easy when write fails with EPIPE or ECONNRESET and logs the message
with em(notice) level instead of em(error). with em(notice) level instead of em(error).
This prevents the log file from being filled with useless error messages This prevents the log file from being filled with useless error messages
when socat is used as a high volume server or proxy where clients often when socat() is used as a high volume server or proxy where clients often
abort the connection.nl() abort the connection.nl()
This option is experimental. This option is experimental.
label(OPTION_END_CLOSE)dit(bf(tt(end-close))) label(OPTION_END_CLOSE)dit(bf(tt(end-close)))
@ -1478,7 +1541,7 @@ label(OPTION_END_CLOSE)dit(bf(tt(end-close)))
terminates the socket even if it is shared by multiple processes. terminates the socket even if it is shared by multiple processes.
tt(close(2)) "unlinks" the socket from the process but keeps it active as tt(close(2)) "unlinks" the socket from the process but keeps it active as
long as there are still links from other processes.nl() long as there are still links from other processes.nl()
Similarly, when an address of type EXEC or SYSTEM is ended, socat usually 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 will explicitely kill the sub process. With this option, it will just close
the file descriptors. the file descriptors.
label(OPTION_IOCTL_VOID)dit(bf(tt(ioctl-void=<request>))) label(OPTION_IOCTL_VOID)dit(bf(tt(ioctl-void=<request>)))
@ -1653,7 +1716,7 @@ Options of this group change the process properties instead of just affecting
one data channel. one data channel.
For EXEC and SYSTEM addresses and for LISTEN and CONNECT type addresses with For EXEC and SYSTEM addresses and for LISTEN and CONNECT type addresses with
option FORK, option FORK,
these options apply to the child processes instead of the main socat process. these options apply to the child processes instead of the main socat() process.
startdit() startdit()
label(OPTION_CHROOT)dit(bf(tt(chroot=<directory>))) label(OPTION_CHROOT)dit(bf(tt(chroot=<directory>)))
Performs a code(chroot()) operation to link(<directory>)(TYPE_DIRECTORY) Performs a code(chroot()) operation to link(<directory>)(TYPE_DIRECTORY)
@ -1701,9 +1764,9 @@ startdit()
label(OPTION_HISTORY)dit(bf(tt(history=<filename>))) label(OPTION_HISTORY)dit(bf(tt(history=<filename>)))
Reads and writes history from/to link(<filename>)(TYPE_FILENAME) (link(example)(EXAMPLE_OPTION_HISTORY)). Reads and writes history from/to link(<filename>)(TYPE_FILENAME) (link(example)(EXAMPLE_OPTION_HISTORY)).
label(OPTION_NOPROMPT)dit(bf(tt(noprompt))) label(OPTION_NOPROMPT)dit(bf(tt(noprompt)))
Since version 1.4.0, socat per default tries to determine a prompt - Since version 1.4.0, socat() per default tries to determine a prompt -
that is then passed to the readline call - by remembering the last that is then passed to the readline call - by remembering the last
incomplete line of the output. With this option, socat does not pass a incomplete line of the output. With this option, socat() does not pass a
prompt to readline, so it begins line editing in the first column prompt to readline, so it begins line editing in the first column
of the terminal. of the terminal.
label(OPTION_NOECHO)dit(bf(tt(noecho=<pattern>))) label(OPTION_NOECHO)dit(bf(tt(noecho=<pattern>)))
@ -1712,12 +1775,12 @@ label(OPTION_NOECHO)dit(bf(tt(noecho=<pattern>)))
The prompt is defined as the text that was output to the readline address The prompt is defined as the text that was output to the readline address
after the lastest newline character and before an input character was after the lastest newline character and before an input character was
typed. The pattern is a regular expression, e.g. typed. The pattern is a regular expression, e.g.
"^[Pp]assword:.*$" or "([Uu]ser:|[Pp]assword:)". See regex(7) for details. "^[Pp]assword:.*$" or "([Uu]ser:|[Pp]assword:)". See regex\(7) for details.
(link(example)(EXAMPLE_OPTION_NOECHO)) (link(example)(EXAMPLE_OPTION_NOECHO))
label(OPTION_PROMPT)dit(bf(tt(prompt=<string>))) label(OPTION_PROMPT)dit(bf(tt(prompt=<string>)))
Passes the string as prompt to the readline function. readline prints this Passes the string as prompt to the readline function. readline prints this
prompt when stepping through the history. If this string matches a constant prompt when stepping through the history. If this string matches a constant
prompt issued by an interactive program on the other socat address, prompt issued by an interactive program on the other socat() address,
consistent look and feel can be archieved. consistent look and feel can be archieved.
enddit() enddit()
@ -1737,7 +1800,7 @@ label(OPTION_CR)dit(bf(tt(cr)))
label(OPTION_CRNL)dit(bf(tt(crnl))) label(OPTION_CRNL)dit(bf(tt(crnl)))
Converts the default line termination character NL ('\n', 0x0a) to/from CRNL Converts the default line termination character NL ('\n', 0x0a) to/from CRNL
("\r\n", 0x0d0a) when writing/reading on this channel (link(example)(EXAMPLE_OPTION_CRNL)). ("\r\n", 0x0d0a) when writing/reading on this channel (link(example)(EXAMPLE_OPTION_CRNL)).
Note: socat simply strips all CR characters. Note: socat() simply strips all CR characters.
label(OPTION_IGNOREEOF)dit(bf(tt(ignoreeof))) label(OPTION_IGNOREEOF)dit(bf(tt(ignoreeof)))
When EOF occurs on this channel, socat() ignores it and tries to read more When EOF occurs on this channel, socat() ignores it and tries to read more
data (like "tail -f") (link(example)(EXAMPLE_OPTION_IGNOREEOF)). data (like "tail -f") (link(example)(EXAMPLE_OPTION_IGNOREEOF)).
@ -1893,7 +1956,7 @@ label(OPTION_SETSOCKOPT_INT)dit(bf(tt(setsockopt-int=<level>:<optname>:<optval>)
set. For the actual numbers you might have to look up the appropriate include set. For the actual numbers you might have to look up the appropriate include
files of your system. The 4th tt(setsockopt()) parameter, tt(value) files of your system. The 4th tt(setsockopt()) parameter, tt(value)
[link(int)(TYPE_INT)], is passed to the function per pointer, and for the [link(int)(TYPE_INT)], is passed to the function per pointer, and for the
length parameter sizeof(int) is taken implicitely. length parameter sizeof\(int) is taken implicitely.
label(OPTION_SETSOCKOPT_BIN)dit(bf(tt(setsockopt-bin=<level>:<optname>:<optval>))) label(OPTION_SETSOCKOPT_BIN)dit(bf(tt(setsockopt-bin=<level>:<optname>:<optval>)))
Like tt(setsockopt-int), but <optval> must be provided in Like tt(setsockopt-int), but <optval> must be provided in
link(dalan)(TYPE_DATA) format and specifies an arbitrary sequence of bytes; link(dalan)(TYPE_DATA) format and specifies an arbitrary sequence of bytes;
@ -2015,7 +2078,7 @@ label(OPTION_RES_DEFNAMES)dit(bf(tt(res-defnames)))
label(OPTION_RES_STAYOPEN)dit(bf(tt(res-stayopen))) label(OPTION_RES_STAYOPEN)dit(bf(tt(res-stayopen)))
label(OPTION_RES_DNSRCH)dit(bf(tt(res-dnsrch))) label(OPTION_RES_DNSRCH)dit(bf(tt(res-dnsrch)))
These options set the corresponding resolver (name resolution) option flags. These options set the corresponding resolver (name resolution) option flags.
Append "=0" to clear a default option. See man resolver(5) for more Append "=0" to clear a default option. See man resolver\(5) for more
information on these options. Note: these options are valid only for the information on these options. Note: these options are valid only for the
address they are applied to. address they are applied to.
@ -2026,7 +2089,7 @@ startdit()enddit()nl()
label(GROUP_IP6)em(bf(IP6 option group)) label(GROUP_IP6)em(bf(IP6 option group))
These options can only be used on IPv6 based sockets. See link(IP These options can only be used on IPv6 based sockets. See link\(IP
options)(GROUP_IP) for options that can be applied to both IPv4 and IPv6 options)(GROUP_IP) for options that can be applied to both IPv4 and IPv6
sockets. sockets.
startdit() startdit()
@ -2122,7 +2185,7 @@ label(OPTION_TCP_CONN_ABORT_THRESHOLD)dit(bf(tt(conn-abort-threshold=<millisecon
Sets the time to wait for an answer of the server during the initial connect Sets the time to wait for an answer of the server during the initial connect
(HP-UX). (HP-UX).
label(OPTION_TCP_KEEPINIT)dit(bf(tt(keepinit))) label(OPTION_TCP_KEEPINIT)dit(bf(tt(keepinit)))
Sets the time to wait for an answer of the server during connect() before Sets the time to wait for an answer of the server during connect\() before
giving up. Value in half seconds, default is 150 (75s) (Tru64). giving up. Value in half seconds, default is 150 (75s) (Tru64).
label(OPTION_TCP_PAWS)dit(bf(tt(paws))) label(OPTION_TCP_PAWS)dit(bf(tt(paws)))
Enables the "protect against wrapped sequence numbers" feature (Tru64). Enables the "protect against wrapped sequence numbers" feature (Tru64).
@ -2158,7 +2221,7 @@ startdit()
label(OPTION_SOURCEPORT)dit(bf(tt(sourceport=<port>))) label(OPTION_SOURCEPORT)dit(bf(tt(sourceport=<port>)))
For outgoing (client) TCP and UDP connections, it sets the source For outgoing (client) TCP and UDP connections, it sets the source
link(<port>)(TYPE_PORT) using an extra code(bind()) call. link(<port>)(TYPE_PORT) using an extra code(bind()) call.
With TCP or UDP listen addresses, socat immediately shuts down the With TCP or UDP listen addresses, socat() immediately shuts down the
connection if the client does not use this sourceport (link(example)(EXAMPLE_OPTION_SOURCEPORT)). connection if the client does not use this sourceport (link(example)(EXAMPLE_OPTION_SOURCEPORT)).
label(OPTION_LOWPORT)dit(bf(tt(lowport))) label(OPTION_LOWPORT)dit(bf(tt(lowport)))
Outgoing (client) TCP and UDP connections with this option use Outgoing (client) TCP and UDP connections with this option use
@ -2199,9 +2262,9 @@ label(OPTION_PROXYPORT)dit(bf(tt(proxyport=<TCP service>)))
link(<TCP service>)(TYPE_TCP_SERVICE). link(<TCP service>)(TYPE_TCP_SERVICE).
label(OPTION_IGNORECR)dit(bf(tt(ignorecr))) label(OPTION_IGNORECR)dit(bf(tt(ignorecr)))
The HTTP protocol requires the use of CR+NL as line terminator. When a proxy The HTTP protocol requires the use of CR+NL as line terminator. When a proxy
server violates this standard, socat might not understand its answer. server violates this standard, socat() might not understand its answer.
This option directs socat to interprete NL as line terminator and This option directs socat() to interprete NL as line terminator and
to ignore CR in the answer. Nevertheless, socat sends CR+NL to the proxy. to ignore CR in the answer. Nevertheless, socat() sends CR+NL to the proxy.
label(OPTION_PROXY_AUTHORIZATION)dit(bf(tt(proxyauth=<username>:<password>))) label(OPTION_PROXY_AUTHORIZATION)dit(bf(tt(proxyauth=<username>:<password>)))
Provide "basic" authentication to the proxy server. The argument to the Provide "basic" authentication to the proxy server. The argument to the
option is used with a "Proxy-Authorization: Base" header in base64 encoded option is used with a "Proxy-Authorization: Base" header in base64 encoded
@ -2210,8 +2273,8 @@ label(OPTION_PROXY_AUTHORIZATION)dit(bf(tt(proxyauth=<username>:<password>)))
in the process list; username and password are transferred to the proxy in the process list; username and password are transferred to the proxy
server unencrypted (base64 encoded) and might be sniffed. server unencrypted (base64 encoded) and might be sniffed.
label(OPTION_PROXY_RESOLVE)dit(bf(tt(resolve))) label(OPTION_PROXY_RESOLVE)dit(bf(tt(resolve)))
Per default, socat sends to the proxy a CONNECT request containing the Per default, socat() sends to the proxy a CONNECT request containing the
target hostname. With this option, socat resolves the hostname locally and target hostname. With this option, socat() resolves the hostname locally and
sends the IP address. Please note that, according to RFC 2396, only name sends the IP address. Please note that, according to RFC 2396, only name
resolution to IPv4 addresses is implemented. resolution to IPv4 addresses is implemented.
enddit() enddit()
@ -2303,27 +2366,31 @@ EXEC or SYSTEM addresses invoke a program using a child process and transfer dat
default, a code(socketpair()) is created and assigned to stdin and stdout of default, a code(socketpair()) is created and assigned to stdin and stdout of
the child process, while stderr is inherited from the socat() process, and the the child process, while stderr is inherited from the socat() process, and the
child process uses file descriptors 0 and 1 for communicating with the main child process uses file descriptors 0 and 1 for communicating with the main
socat process. socat() process.
startdit() startdit()
label(OPTION_NOFORK)dit(bf(tt(nofork))) label(OPTION_NOFORK)dit(bf(tt(nofork)))
Does not fork a subprocess for executing the program, instead calls execvp() Does not fork a subprocess for executing the program, instead calls execvp\()
or system() directly from the actual socat instance. This avoids the or system\() directly from the actual socat() instance. This avoids the
overhead of another process between the program and its peer, overhead of another process between the program and its peer,
but introduces a lot of restrictions: but introduces a lot of restrictions:
startit() startit()
it() this option can only be applied to the second socat() address. it() this option can only be applied to the second socat() address.
it() it cannot be applied to a part of a link(dual)(ADDRESS_DUAL) address. it() it cannot be applied to a part of a link(dual)(ADDRESS_DUAL) address.
it() the first socat address cannot be OPENSSL or READLINE it() the first socat() address cannot be OPENSSL or READLINE
it() socat options -b, -t, -D, -l, -v, -x become useless it() socat() options -b, -t, -D, -l, -v, -x become useless
it() for both addresses, options ignoreeof, cr, and crnl become useless it() for both addresses, options ignoreeof, cr, and crnl become useless
it() for the second address (the one with option nofork), options it() for the second address (the one with option nofork), options
append, metaCOMMENT(async,) cloexec, flock, user, group, mode, nonblock, append, metaCOMMENT(async,) cloexec, flock, user, group, mode, nonblock,
perm-late, setlk, and setpgid cannot be applied. Some of these could be perm-late, setlk, and setpgid cannot be applied. Some of these could be
used on the first address though. used on the first address though.
endit() endit()
label(OPTION_COMMTYPE)dit(bf(tt(commtype=<commtype>)))
Specifies the kind of file descriptors that are generated for communication
between the socat() process and the left side of the program. See
link(commtype)(TYPE_COMMTYPE) for supported values and their meanings.
label(OPTION_PIPES)dit(bf(tt(pipes))) label(OPTION_PIPES)dit(bf(tt(pipes)))
Creates a pair of unnamed pipes for interprocess communication instead of a Creates a pair of unnamed pipes for interprocess communication instead of a
socket pair. socket pair (obsolete, use option link(commtype)(OPTION_COMMTYPE) instead).
label(OPTION_OPENPTY)dit(bf(tt(openpty))) label(OPTION_OPENPTY)dit(bf(tt(openpty)))
Establishes communication with the sub process using a pseudo terminal Establishes communication with the sub process using a pseudo terminal
created with code(openpty()) instead of the default (socketpair or ptmx). created with code(openpty()) instead of the default (socketpair or ptmx).
@ -2335,7 +2402,8 @@ label(OPTION_PTY)dit(bf(tt(pty)))
Establishes communication with the sub process using a pseudo terminal Establishes communication with the sub process using a pseudo terminal
instead of a socket pair. Creates the pty with an available mechanism. If instead of a socket pair. Creates the pty with an available mechanism. If
openpty and ptmx are both available, it uses ptmx because this is POSIX openpty and ptmx are both available, it uses ptmx because this is POSIX
compliant (link(example)(EXAMPLE_OPTION_PTY)). compliant (obsolete, use option link(commtype)(OPTION_COMMTYPE) instead)
(link(example)(EXAMPLE_OPTION_PTY)).
label(OPTION_CTTY)dit(bf(tt(ctty))) label(OPTION_CTTY)dit(bf(tt(ctty)))
Makes the pty the controlling tty of the sub process (link(example)(EXAMPLE_OPTION_CTTY)). Makes the pty the controlling tty of the sub process (link(example)(EXAMPLE_OPTION_CTTY)).
label(OPTION_STDERR)dit(bf(tt(stderr))) label(OPTION_STDERR)dit(bf(tt(stderr)))
@ -2353,7 +2421,7 @@ label(OPTION_FDOUT)dit(bf(tt(fdout=<fdnum>)))
this fd for writing data to socat() (link(example)(EXAMPLE_OPTION_FDOUT)). this fd for writing data to socat() (link(example)(EXAMPLE_OPTION_FDOUT)).
label(OPTION_SIGHUP)label(OPTION_SIGINT)label(OPTION_SIGQUIT)dit(bf(tt(sighup)), bf(tt(sigint)), bf(tt(sigquit))) label(OPTION_SIGHUP)label(OPTION_SIGINT)label(OPTION_SIGQUIT)dit(bf(tt(sighup)), bf(tt(sigint)), bf(tt(sigquit)))
Has socat() pass an eventual signal of this type to the sub process. Has socat() pass an eventual signal of this type to the sub process.
If no address has this option, socat terminates on these signals. If no address has this option, socat() terminates on these signals.
enddit() enddit()
startdit()enddit()nl() startdit()enddit()nl()
@ -2544,9 +2612,9 @@ label(OPTION_SYMBOLIC_LINK)dit(bf(tt(link=<filename>)))
the address is closed (but see option link(unlink-close)(OPTION_UNLINK_CLOSE)). the address is closed (but see option link(unlink-close)(OPTION_UNLINK_CLOSE)).
label(OPTION_PTY_WAIT_SLAVE)dit(bf(tt(wait-slave))) label(OPTION_PTY_WAIT_SLAVE)dit(bf(tt(wait-slave)))
Blocks the open phase until a process opens the slave side of the pty. Blocks the open phase until a process opens the slave side of the pty.
Usually, socat continues after generating the pty with opening the next Usually, socat() continues after generating the pty with opening the next
address or with entering the transfer loop. With the wait-slave option, address or with entering the transfer loop. With the wait-slave option,
socat waits until some process opens the slave side of the pty before socat() waits until some process opens the slave side of the pty before
continuing. continuing.
This option only works if the operating system provides the tt(poll()) This option only works if the operating system provides the tt(poll())
system call. And it depends on an undocumented behaviour of pty's, so it system call. And it depends on an undocumented behaviour of pty's, so it
@ -2629,14 +2697,14 @@ label(OPTION_OPENSSL_PSEUDO)dit(bf(tt(pseudo)))
gathering daemon can be utilized, this option activates a mechanism for gathering daemon can be utilized, this option activates a mechanism for
providing pseudo entropy. This is archieved by taking the current time in providing pseudo entropy. This is archieved by taking the current time in
microseconds for feeding the libc pseudo random number generator with an microseconds for feeding the libc pseudo random number generator with an
initial value. openssl is then feeded with output from random() calls.nl() initial value. openssl is then feeded with output from random\() calls.nl()
NOTE:This mechanism is not sufficient for generation of secure keys! NOTE:This mechanism is not sufficient for generation of secure keys!
label(OPTION_OPENSSL_FIPS)dit(bf(tt(fips))) label(OPTION_OPENSSL_FIPS)dit(bf(tt(fips)))
Enables FIPS mode if compiled in. For info about the FIPS encryption Enables FIPS mode if compiled in. For info about the FIPS encryption
implementation standard see lurl(http://oss-institute.org/fips-faq.html). implementation standard see lurl(http://oss-institute.org/fips-faq.html).
This mode might require that the involved certificates are generated with a This mode might require that the involved certificates are generated with a
FIPS enabled version of openssl. Setting or clearing this option on one FIPS enabled version of openssl. Setting or clearing this option on one
socat address affects all OpenSSL addresses of this process. socat() address affects all OpenSSL addresses of this process.
enddit() enddit()
startdit()enddit()nl() startdit()enddit()nl()
@ -2667,7 +2735,7 @@ Options that control Linux TUN/TAP interface device addresses.
startdit() startdit()
label(OPTION_TUN_DEVICE)dit(bf(tt(tun-device=<device-file>))) label(OPTION_TUN_DEVICE)dit(bf(tt(tun-device=<device-file>)))
Instructs socat to take another path for the TUN clone device. Default is Instructs socat() to take another path for the TUN clone device. Default is
tt(/dev/net/tun). tt(/dev/net/tun).
label(OPTION_TUN_NAME)dit(bf(tt(tun-name=<if-name>))) label(OPTION_TUN_NAME)dit(bf(tt(tun-name=<if-name>)))
Gives the resulting network interface a specific name instead of the system Gives the resulting network interface a specific name instead of the system
@ -2737,6 +2805,20 @@ label(TYPE_BYTE)dit(byte)
label(TYPE_COMMAND_LINE)dit(command-line) label(TYPE_COMMAND_LINE)dit(command-line)
A string specifying a program name and its arguments, separated by single A string specifying a program name and its arguments, separated by single
spaces. spaces.
label(TYPE_COMMTYPE)dit(commtype)
One of the following supported strings:
startdit()
label(TYPE_COMMTYPE_SOCKETPAIR)dit(bf(tt(socketpair)))A single UNIX domain
socket pair.
label(TYPE_COMMTYPE_SOCKETPAIRS)dit(bf(tt(socketpairs)))Two UNIX domain
socket pairs for bidirectional transfer, or one in case of unidirectional
transfer. This type is the default.
label(TYPE_COMMTYPE_PIPES)dit(bf(tt(pipes)))Two pipes, or one in case of
unidirectional transfer.
label(TYPE_COMMTYPE_TCP)dit(bf(tt(tcp)))One pair of TCP sockets.
label(TYPE_COMMTYPE_PTYS)dit(bf(tt(ptys)))Two PTYs or one in case of
unidirectional transfer. The slave sides are used for writing.
enddit()
label(TYPE_DATA)dit(data) label(TYPE_DATA)dit(data)
A raw data specification following em(dalan) syntax. Currently the only A raw data specification following em(dalan) syntax. Currently the only
valid form is a string starting with 'x' followed by an even number of hex valid form is a string starting with 'x' followed by an even number of hex
@ -2801,7 +2883,7 @@ label(TYPE_SOCKNAME)dit(sockname)
A socket address. See address-option link(`bind')(OPTION_BIND) A socket address. See address-option link(`bind')(OPTION_BIND)
label(TYPE_STRING)dit(string) label(TYPE_STRING)dit(string)
A sequence of characters, not containing '\0' and, depending on A sequence of characters, not containing '\0' and, depending on
the position within the command line, ':', ',', or "!!". Note the position within the command line, ':', ',', or "%". Note
that you might have to escape shell meta characters in the command line. that you might have to escape shell meta characters in the command line.
label(TYPE_TCP_SERVICE)dit(TCP service) label(TYPE_TCP_SERVICE)dit(TCP service)
A service name, not starting with a digit, that is resolved by A service name, not starting with a digit, that is resolved by
@ -2896,7 +2978,7 @@ nobody after forking; it only permits connections from the private 10 network
(link(range)(OPTION_RANGE)); due to link(reuseaddr)(OPTION_REUSEADDR), it (link(range)(OPTION_RANGE)); due to link(reuseaddr)(OPTION_REUSEADDR), it
allows immediate restart after master process's termination, even if some child allows immediate restart after master process's termination, even if some child
sockets are not completely shut down. sockets are not completely shut down.
With link(-lmlocal2)(option_lm), socat logs to stderr until successfully With link(-lmlocal2)(option_lm), socat() logs to stderr until successfully
reaching the accept loop. Further logging is directed to syslog with facility reaching the accept loop. Further logging is directed to syslog with facility
local2. local2.
@ -2965,7 +3047,7 @@ opens an interactive connection via the serial line, e.g. for talking with a
modem. link(raw)(OPTION_RAW) and link(echo)(OPTION_ECHO) set the console's and modem. link(raw)(OPTION_RAW) and link(echo)(OPTION_ECHO) set the console's and
ttyS0's terminal parameters to practicable values, link(crnl)(OPTION_CRNL) ttyS0's terminal parameters to practicable values, link(crnl)(OPTION_CRNL)
converts to correct newline characters. link(escape)(OPTION_ESCAPE) allows to converts to correct newline characters. link(escape)(OPTION_ESCAPE) allows to
terminate the socat process with character control-O. terminate the socat() process with character control-O.
Consider using link(READLINE)(ADDRESS_READLINE) instead of the first address. Consider using link(READLINE)(ADDRESS_READLINE) instead of the first address.
@ -3044,7 +3126,7 @@ htmlcommand(<dt><code><strong>socat -u TCP4-LISTEN:3334,reuseaddr,fork \</strong
implements a simple network based message collector. implements a simple network based message collector.
For each client connecting to port 3334, a new child process is generated (option link(fork)(OPTION_FORK)). For each client connecting to port 3334, a new child process is generated (option link(fork)(OPTION_FORK)).
All data sent by the clients are link(append)(OPTION_APPEND)'ed to the file /tmp/in.log. All data sent by the clients are link(append)(OPTION_APPEND)'ed to the file /tmp/in.log.
If the file does not exist, socat link(creat)(OPTION_CREAT)'s it. If the file does not exist, socat() link(creat)(OPTION_CREAT)'s it.
Option link(reuseaddr)(OPTION_REUSEADDR) allows immediate restart of the server Option link(reuseaddr)(OPTION_REUSEADDR) allows immediate restart of the server
process. process.
@ -3090,7 +3172,7 @@ device (link(PTY)(ADDRESS_PTY)) on the client that can be reached under the
symbolic link(link)(OPTION_SYMBOLIC_LINK) file($HOME/dev/vmodem0). symbolic link(link)(OPTION_SYMBOLIC_LINK) file($HOME/dev/vmodem0).
An application that expects a serial line or modem An application that expects a serial line or modem
can be configured to use file($HOME/dev/vmodem0); its traffic will be directed can be configured to use file($HOME/dev/vmodem0); its traffic will be directed
to a modemserver via ssh where another socat instance links it with to a modemserver via ssh where another socat() instance links it with
file(/dev/ttyS0). file(/dev/ttyS0).
@ -3121,7 +3203,7 @@ Otherwise the connection is terminated.
With link(cert)(OPTION_OPENSSL_CERTIFICATE) a file containing the client certificate With link(cert)(OPTION_OPENSSL_CERTIFICATE) a file containing the client certificate
and the associated private key is specified. This is required in case the and the associated private key is specified. This is required in case the
server wishes a client authentication; many Internet servers do not.nl() server wishes a client authentication; many Internet servers do not.nl()
The first address ('-') can be replaced by almost any other socat address. The first address ('-') can be replaced by almost any other socat() address.
label(EXAMPLE_ADDRESS_OPENSSL_LISTEN) label(EXAMPLE_ADDRESS_OPENSSL_LISTEN)
@ -3133,7 +3215,7 @@ verified against cafile.crt.nl()
The second address ('PIPE') can be replaced by almost any other socat The second address ('PIPE') can be replaced by almost any other socat
address.nl() address.nl()
For instructions on generating and distributing OpenSSL keys and certificates For instructions on generating and distributing OpenSSL keys and certificates
see the additional socat docu tt(socat-openssl.txt). see the additional socat() docu tt(socat-openssl.txt).
dit(bf(tt(echo |socat -u - file:/tmp/bigfile,create,largefile,seek=100000000000))) dit(bf(tt(echo |socat -u - file:/tmp/bigfile,create,largefile,seek=100000000000)))
@ -3171,8 +3253,8 @@ dit(bf(tt(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 merges data arriving from different TCP streams on port 8888 to just one stream
to target:9999. The link(end-close)(OPTION_END_CLOSE) option prevents the child to target:9999. The link(end-close)(OPTION_END_CLOSE) option prevents the child
processes forked off by the second address from terminating the shared 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 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 as the parent process lives; shutdown\(2) would actively terminate the
connection). connection).
@ -3195,7 +3277,7 @@ tt(SO_BROADCAST).
label(EXAMPLE_ADDRESS_IP4_BROADCAST_CLIENT) label(EXAMPLE_ADDRESS_IP4_BROADCAST_CLIENT)
dit(bf(tt(socat - IP4-DATAGRAM:255.255.255.255:44,broadcast,range=10.0.0.0/8))) dit(bf(tt(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 sends a broadcast to the local network\(s) using protocol 44. Accepts replies
from the private address range only. from the private address range only.
@ -3228,7 +3310,7 @@ dit(bf(tt(socat PTY,link=/var/run/ppp,raw,echo=0 INTERFACE:hdlc0)))
circumvents the problem that pppd requires a serial device and thus might not circumvents the problem that pppd requires a serial device and thus might not
be able to work on a synchronous line that is represented by a network device. be able to work on a synchronous line that is represented by a network device.
socat creates a PTY to make pppd happy, binds to the network socat() creates a PTY to make pppd happy, binds to the network
link(interface)(ADDRESS_INTERFACE) tt(hdlc0), and can transfer data between link(interface)(ADDRESS_INTERFACE) tt(hdlc0), and can transfer data between
both devices. Use pppd on device tt(/var/run/ppp) then. both devices. Use pppd on device tt(/var/run/ppp) then.
@ -3243,7 +3325,7 @@ servers), and the original client request.
label(EXAMPLE_ANCILLARY) label(EXAMPLE_ANCILLARY)
dit(bf(tt(socat -d -d UDP4-RECVFROM:9999,so-broadcast,so-timestamp,ip-pktinfo,ip-recverr,ip-recvopts,ip-recvtos,ip-recvttl!!- SYSTEM:'export; sleep 1' |grep SOCAT))) dit(bf(tt(socat -d -d -%UDP4-RECVFROM:9999,so-broadcast,so-timestamp,ip-pktinfo,ip-recverr,ip-recvopts,ip-recvtos,ip-recvttl SYSTEM:'export; sleep 1' |grep SOCAT)))
waits for incoming UDP packets on port 9999 and prints the environment waits for incoming UDP packets on port 9999 and prints the environment
variables provided by socat. On BSD based systems you have to replace variables provided by socat. On BSD based systems you have to replace
@ -3308,7 +3390,7 @@ label(ENVIRONMENT_VARIABLES)
manpagesection(ENVIRONMENT VARIABLES) manpagesection(ENVIRONMENT VARIABLES)
Input variables carry information from the environment to socat, output Input variables carry information from the environment to socat, output
variables are set by socat for use in executed scripts and programs. variables are set by socat() for use in executed scripts and programs.
In the output variables beginning with "SOCAT" this prefix is actually replaced In the output variables beginning with "SOCAT" this prefix is actually replaced
by the upper case name of the executable or the value of option by the upper case name of the executable or the value of option
@ -3319,29 +3401,32 @@ label(ENV_SOCAT_DEFAULT_LISTEN_IP)
dit(bf(SOCAT_DEFAULT_LISTEN_IP) (input)) (Values 4 or 6) Sets the IP version to dit(bf(SOCAT_DEFAULT_LISTEN_IP) (input)) (Values 4 or 6) Sets the IP version to
be used for listen, recv, and recvfrom addresses if no be used for listen, recv, and recvfrom addresses if no
link(pf)(OPTION_PROTOCOL_FAMILY) (protocol-family) option is given. Is link(pf)(OPTION_PROTOCOL_FAMILY) (protocol-family) option is given. Is
overridden by socat options link(-4)(option_4) or link(-6)(option_6). overridden by socat() options link(-4)(option_4) or link(-6)(option_6).
dit(bf(SOCAT_PREFERRED_RESOLVE_IP) (input)) (Values 0, 4, or 6) Sets the IP dit(bf(SOCAT_PREFERRED_RESOLVE_IP) (input)) (Values 0, 4, or 6) Sets the IP
version to version to
be used when resolving target host names when version is not specified by be used when resolving target host names when version is not specified by
address type, option link(pf)(OPTION_PROTOCOL_FAMILY) (protocol-family), or address type, option link(pf)(OPTION_PROTOCOL_FAMILY) (protocol-family), or
address format. If name resolution does not return a matching entry, the first address format. If name resolution does not return a matching entry, the first
result (with differing IP version) is taken. With value 0, socat always selects result (with differing IP version) is taken. With value 0, socat() always selects
the first record and its IP version. the first record and its IP version.
dit(bf(SOCAT_FORK_WAIT) (input)) Specifies the time (seconds) to sleep the dit(bf(SOCAT_MAIN_WAIT) (input)) Specifies the time (seconds) to sleep the
parent and child processes after successful fork(). Useful for debugging. socat() process immediately after start. Useful for debugging.
dit(bf(SOCAT_VERSION) (output)) Socat sets this variable to its version string, dit(bf(SOCAT_FORK_WAIT) (input)) Specifies the time (seconds) to sleep the
parent and child processes after successful fork\(). Useful for debugging.
dit(bf(SOCAT_VERSION) (output)) Socat() sets this variable to its version string,
e.g. tt("1.7.0.0") for released versions or e.g. tt("1.6.0.1+envvar") for e.g. tt("1.7.0.0") for released versions or e.g. tt("1.6.0.1+envvar") for
temporary versions; can be used in scripts invoked by socat. temporary versions; can be used in scripts invoked by socat.
dit(bf(SOCAT_PID) (output)) Socat sets this variable to its process id. In case dit(bf(SOCAT_PID) (output)) Socat() sets this variable to its process id. In case
of link(fork)(OPTION_FORK) address option, SOCAT_PID gets the child processes of link(fork)(OPTION_FORK) address option, SOCAT_PID gets the child processes
id. Forking for link(exec)(ADDRESS_EXEC) and link(system)(ADDRESS_SYSTEM) does id. Forking for link(exec)(ADDRESS_EXEC) and link(system)(ADDRESS_SYSTEM) does
not change SOCAT_PID. not change SOCAT_PID.
dit(bf(SOCAT_PPID) (output)) Socat sets this variable to its process id. In dit(bf(SOCAT_PPID) (output)) Socat() sets this variable to its process id. In
case of link(fork)(OPTION_FORK), SOCAT_PPID keeps the pid of the master process. case of link(fork)(OPTION_FORK), SOCAT_PPID keeps the pid of the master process.
dit(bf(SOCAT_PEERADDR) (output)) With passive socket addresses (all LISTEN and dit(bf(SOCAT_PEERADDR) (output)) With passive socket addresses (all LISTEN and
@ -3362,49 +3447,49 @@ link(SCTP-LISTEN)(ADDRESS_SCTP_LISTEN) addresses, this variable is set to the
local port. local port.
dit(bf(SOCAT_TIMESTAMP) (output)) With all RECVFROM addresses where address dit(bf(SOCAT_TIMESTAMP) (output)) With all RECVFROM addresses where address
option link(so-timestamp)(OPTION_SO_TIMESTAMP) is applied, socat sets this option link(so-timestamp)(OPTION_SO_TIMESTAMP) is applied, socat() sets this
variable to the resulting timestamp. variable to the resulting timestamp.
dit(bf(SOCAT_IP_OPTIONS) (output)) With all IPv4 based RECVFROM addresses where dit(bf(SOCAT_IP_OPTIONS) (output)) With all IPv4 based RECVFROM addresses where
address option link(ip-recvopts)(OPTION_IP_RECVOPTS) is applied, socat fills address option link(ip-recvopts)(OPTION_IP_RECVOPTS) is applied, socat() fills
this variable with the IP options of the received packet. this variable with the IP options of the received packet.
dit(bf(SOCAT_IP_DSTADDR) (output)) With all IPv4 based RECVFROM addresses where dit(bf(SOCAT_IP_DSTADDR) (output)) With all IPv4 based RECVFROM addresses where
address option link(ip-recvdstaddr)(OPTION_IP_RECVDSTADDR) (BSD) or address option link(ip-recvdstaddr)(OPTION_IP_RECVDSTADDR) (BSD) or
link(ip-pktinfo)(OPTION_IP_PKTINFO) (other platforms) is applied, socat sets link(ip-pktinfo)(OPTION_IP_PKTINFO) (other platforms) is applied, socat() sets
this variable to the destination address of the received packet. This is this variable to the destination address of the received packet. This is
particularly useful to identify broadcast and multicast addressed packets. particularly useful to identify broadcast and multicast addressed packets.
dit(bf(SOCAT_IP_IF) (output)) With all IPv4 based RECVFROM addresses where dit(bf(SOCAT_IP_IF) (output)) With all IPv4 based RECVFROM addresses where
address option link(ip-recvif)(OPTION_IP_RECVIF) (BSD) or address option link(ip-recvif)(OPTION_IP_RECVIF) (BSD) or
link(ip-pktinfo)(OPTION_IP_PKTINFO) (other platforms) is applied, socat sets link(ip-pktinfo)(OPTION_IP_PKTINFO) (other platforms) is applied, socat() sets
this variable to the name of the interface where the packet was received. this variable to the name of the interface where the packet was received.
dit(bf(SOCAT_IP_LOCADDR) (output)) With all IPv4 based RECVFROM dit(bf(SOCAT_IP_LOCADDR) (output)) With all IPv4 based RECVFROM
addresses where address option link(ip-pktinfo)(OPTION_IP_PKTINFO) is applied, addresses where address option link(ip-pktinfo)(OPTION_IP_PKTINFO) is applied,
socat sets this variable to the address of the interface where the packet was socat() sets this variable to the address of the interface where the packet was
received. received.
dit(bf(SOCAT_IP_TOS) (output)) With all IPv4 based RECVFROM addresses where dit(bf(SOCAT_IP_TOS) (output)) With all IPv4 based RECVFROM addresses where
address option link(ip-recvtos)(OPTION_IP_RECVTOS) is applied, socat sets this address option link(ip-recvtos)(OPTION_IP_RECVTOS) is applied, socat() sets this
variable to the TOS (type of service) of the received packet. variable to the TOS (type of service) of the received packet.
dit(bf(SOCAT_IP_TTL) (output)) With all IPv4 based RECVFROM addresses where dit(bf(SOCAT_IP_TTL) (output)) With all IPv4 based RECVFROM addresses where
address option link(ip-recvttl)(OPTION_IP_RECVTTL) is applied, socat sets this address option link(ip-recvttl)(OPTION_IP_RECVTTL) is applied, socat() sets this
variable to the TTL (time to live) of the received packet. variable to the TTL (time to live) of the received packet.
dit(bf(SOCAT_IPV6_HOPLIMIT) (output)) With all IPv6 based RECVFROM addresses dit(bf(SOCAT_IPV6_HOPLIMIT) (output)) With all IPv6 based RECVFROM addresses
where address option link(ipv6-recvhoplimit)(OPTION_IPV6_RECVHOPLIMIT) is where address option link(ipv6-recvhoplimit)(OPTION_IPV6_RECVHOPLIMIT) is
applied, socat sets this variable to the hoplimit value of the received packet. applied, socat() sets this variable to the hoplimit value of the received packet.
dit(bf(SOCAT_IPV6_DSTADDR) (output)) With all IPv6 based RECVFROM dit(bf(SOCAT_IPV6_DSTADDR) (output)) With all IPv6 based RECVFROM
addresses where address option link(ipv6-recvpktinfo)(OPTION_IPV6_RECVPKTINFO) addresses where address option link(ipv6-recvpktinfo)(OPTION_IPV6_RECVPKTINFO)
is applied, socat sets this variable to the destination address of the received is applied, socat() sets this variable to the destination address of the received
packet. packet.
dit(bf(SOCAT_IPV6_TCLASS) (output)) With all IPv6 based RECVFROM addresses dit(bf(SOCAT_IPV6_TCLASS) (output)) With all IPv6 based RECVFROM addresses
where address option link(ipv6-recvtclass)(OPTION_IPV6_RECVTCLASS) is applied, where address option link(ipv6-recvtclass)(OPTION_IPV6_RECVTCLASS) is applied,
socat sets this variable to the transfer class of the received packet. socat() sets this variable to the transfer class of the received packet.
dit(bf(HOSTNAME) (input)) Is used to determine the hostname for logging (see dit(bf(HOSTNAME) (input)) Is used to determine the hostname for logging (see
link(-lh)(option_lh)). link(-lh)(option_lh)).
@ -3455,13 +3540,13 @@ standard specifications available on the Internet for free.
label(VERSION) label(VERSION)
manpagesection(VERSION) manpagesection(VERSION)
This man page describes version 2.0.0-b2 of socat(). This man page describes version 2.0.0-b3 of socat().
label(BUGS) label(BUGS)
manpagebugs() manpagebugs()
Addresses cannot be nested, so a single socat process cannot, e.g., drive ssl Addresses cannot be nested, so a single socat() process cannot, e.g., drive ssl
over socks. over socks.
Address option ftruncate without value uses default 1 instead of 0. Address option ftruncate without value uses default 1 instead of 0.
@ -3479,8 +3564,8 @@ label(SEEALSO)
manpageseealso() manpageseealso()
COMMENT(procan\(1), filan\(1), ) COMMENT(procan\(1), filan\(1), )
nc(1), netcat6(1), sock(1), rinetd(8), cage(1), socks.conf(5), openssl(1), nc\(1), netcat6\(1), sock\(1), rinetd\(8), cage\(1), socks.conf\(5),
stunnel(8), pty(1), rlwrap(1), setsid(1) openssl\(1), stunnel\(8), pty\(1), rlwrap\(1), setsid\(1)
Socat() home page lurl(http://www.dest-unreach.org/socat/) Socat() home page lurl(http://www.dest-unreach.org/socat/)

View file

@ -1,6 +1,6 @@
#! /bin/bash #! /bin/bash
# source: proxyecho.sh # source: proxyecho.sh
# Copyright Gerhard Rieger 2003 # Copyright Gerhard Rieger 2003-2009
# Published under the GNU General Public License V.2, see file COPYING # Published under the GNU General Public License V.2, see file COPYING
# perform primitive simulation of a proxy server with echo function via stdio. # perform primitive simulation of a proxy server with echo function via stdio.
@ -56,4 +56,4 @@ echo "HTTP/1.0${SPACES}200 OK"
echo echo
# perform echo function # perform echo function
$CAT exec $CAT

21
socat.c
View file

@ -1,9 +1,9 @@
/* source: socat.c */ /* source: socat.c */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this is the main source, including command line option parsing, general /* this is the main source, including command line option parsing and general
control, and the data shuffler */ control */
#include "config.h" #include "config.h"
#include "xioconfig.h" /* what features are enabled */ #include "xioconfig.h" /* what features are enabled */
@ -220,6 +220,21 @@ int main(int argc, const char *argv[]) {
xioopts.preferred_ip = arg1[0][1]; xioopts.preferred_ip = arg1[0][1];
break; break;
#endif /* WITH_IP4 || WITH_IP6 */ #endif /* WITH_IP4 || WITH_IP6 */
case 'c':
switch (arg1[0][2]) {
case 'S': xioparams->pipetype = XIOCOMM_SOCKETPAIRS; break;
case 'P':
case 'p': xioparams->pipetype = XIOCOMM_PIPES; break;
case 's': xioparams->pipetype = XIOCOMM_SOCKETPAIR; break;
case 'Y': xioparams->pipetype = XIOCOMM_PTYS; break;
case 'y': xioparams->pipetype = XIOCOMM_PTY; break;
case 't': xioparams->pipetype = XIOCOMM_TCP; break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
xioparams->pipetype = atoi(&arg1[0][2]); break;
default: Error1("bad chain communication type \"%s\"", &arg1[0][2]);
}
break;
case '\0': case '\0':
case '-': /*! this is hardcoded "--" */ case '-': /*! this is hardcoded "--" */
case ',': case ',':

View file

@ -1,5 +1,5 @@
/* source: sycls.c */ /* source: sycls.c */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* explicit system call and C library trace function, for those who miss strace /* explicit system call and C library trace function, for those who miss strace
@ -742,6 +742,7 @@ int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
return result; return result;
} }
#if 0
/* we only show the first word of the fd_set's; hope this is enough for most /* we only show the first word of the fd_set's; hope this is enough for most
cases. */ cases. */
int Pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, int Pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
@ -776,6 +777,7 @@ int Pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
errno = _errno; errno = _errno;
return result; return result;
} }
#endif /* 0 */
pid_t Fork(void) { pid_t Fork(void) {
pid_t pid; pid_t pid;

334
test.sh
View file

@ -1,6 +1,6 @@
#! /bin/bash #! /bin/bash
# source: test.sh # source: test.sh
# Copyright Gerhard Rieger 2001-2008 # Copyright Gerhard Rieger 2001-2009
# Published under the GNU General Public License V.2, see file COPYING # Published under the GNU General Public License V.2, see file COPYING
# perform lots of tests on socat # perform lots of tests on socat
@ -2215,70 +2215,38 @@ esac
N=$((N+1)) N=$((N+1))
NAME=EXECSOCKET #EXECSOCKET SYSTEMSOCKET EXECPIPES SYSTEMPIPES EXECPTY SYSTEMPTY
while read commtype feature addropts; do
COMMTYPE="$(echo $commtype |tr a-z A-Z)"
if [ -z "$COMMTYPE" ] || [[ "$COMMTYPE" == \#* ]]; then continue; fi
for EXEC in EXEC SYSTEM
do exec="$(echo $EXEC |tr A-Z a-z)"
NAME=${EXEC}$COMMTYPE
case "$TESTS" in case "$TESTS" in
*%functions%*|*%exec%*|*%$NAME%*) *%functions%*|*%$commtype%*|*%$exec%*|*%$NAME%*)
TEST="$NAME: simple echo via exec of cat with socketpair" TEST="$NAME: simple echo via $exec() of cat using $commtype"
testecho "$N" "$TEST" "" "exec:$CAT" "$opts"
esac
N=$((N+1))
NAME=SYSTEMSOCKET
case "$TESTS" in
*%functions%*|*%system%*|*%$NAME%*)
TEST="$NAME: simple echo via system() of cat with socketpair"
testecho "$N" "$TEST" "" "system:$CAT" "$opts" "$val_t"
esac
N=$((N+1))
NAME=EXECPIPES
case "$TESTS" in
*%functions%*|*%pipe%*|*%$NAME%*)
TEST="$NAME: simple echo via exec of cat with pipes"
testecho "$N" "$TEST" "" "exec:$CAT,pipes" "$opts"
esac
N=$((N+1))
NAME=SYSTEMPIPES
case "$TESTS" in
*%functions%*|*%pipes%*|*%$NAME%*)
TEST="$NAME: simple echo via system() of cat with pipes"
testecho "$N" "$TEST" "" "system:$CAT,pipes" "$opts"
esac
N=$((N+1))
NAME=EXECPTY
case "$TESTS" in
*%functions%*|*%exec%*|*%pty%*|*%$NAME%*)
TEST="$NAME: simple echo via exec of cat with pseudo terminal"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! testaddrs pty >/dev/null; then elif [ "$feature" != . ] && ! testaddrs $feature >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}$commtype not available${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
else else
testecho "$N" "$TEST" "" "exec:$CAT,pty,$PTYOPTS" "$opts" testecho "$N" "$TEST" "" "$exec:$CAT,commtype=$commtype,$addropts" "$opts" "$val_t"
fi fi
esac esac
N=$((N+1)) N=$((N+1))
done
done <<<"
pipes .
pty pty raw,echo=0
socketpair .
ptys pty raw,echo=0
tcp tcp
socketpairs .
"
NAME=SYSTEMPTY
case "$TESTS" in
*%functions%*|*%system%*|*%pty%*|*%$NAME%*)
TEST="$NAME: simple echo via system() of cat with pseudo terminal"
if ! eval $NUMCOND; then :;
elif ! testaddrs pty >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
testecho "$N" "$TEST" "" "system:$CAT,pty,$PTYOPTS" "$opts"
fi
esac
N=$((N+1))
NAME=SYSTEMPIPESFDS NAME=SYSTEMPIPESFDS
@ -3751,7 +3719,8 @@ NAME=CHAINUNIDIR
case "$TESTS" in case "$TESTS" in
*%functions%*|*%chain%*|*%$NAME%*) *%functions%*|*%chain%*|*%$NAME%*)
TEST="$NAME: two unidirectional chains" TEST="$NAME: two unidirectional chains"
testchain "$N" "$TEST" "test|stdin" "test|stdout" "-u $opts" "<>" # on Linux (Debian lenny/sid) we need MISCDELAY due to a weakness/bug
testchain "$N" "$TEST" "test|stdin" "test|stdout" "-u $opts" "<>" "$val_t"
esac esac
N=$((N+1)) N=$((N+1))
@ -3759,7 +3728,7 @@ NAME=CHAINREVDIR
case "$TESTS" in case "$TESTS" in
*%functions%*|*%chain%*|*%$NAME%*) *%functions%*|*%chain%*|*%$NAME%*)
TEST="$NAME: two unidirectional chains, right to left" TEST="$NAME: two unidirectional chains, right to left"
testchain "$N" "$TEST" "^test|stdout" "^test|stdin" "-U $opts" "><" testchain "$N" "$TEST" "^test|stdout" "^test|stdin" "-U $opts" "><" "$val_t"
esac esac
N=$((N+1)) N=$((N+1))
@ -3806,7 +3775,7 @@ N=$((N+1))
NAME=OPENSSL_TCP4 NAME=OPENSSL_TCP4
case "$TESTS" in case "$TESTS" in
*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) *%functions%*|*%chain%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
TEST="$NAME: openssl connect" TEST="$NAME: openssl connect"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! testaddrs openssl >/dev/null; then elif ! testaddrs openssl >/dev/null; then
@ -3859,7 +3828,7 @@ N=$((N+1))
NAME=OPENSSLLISTEN_TCP4 NAME=OPENSSLLISTEN_TCP4
case "$TESTS" in case "$TESTS" in
*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) *%functions%*|*%chain%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
TEST="$NAME: openssl listen" TEST="$NAME: openssl listen"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! testaddrs openssl >/dev/null; then elif ! testaddrs openssl >/dev/null; then
@ -4136,7 +4105,7 @@ N=$((N+1))
NAME=SOCKS4CONNECT_TCP4 NAME=SOCKS4CONNECT_TCP4
case "$TESTS" in case "$TESTS" in
*%functions%*|*%socks%*|*%socks4%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) *%functions%*|*%chain%*|*%socks%*|*%socks4%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
TEST="$NAME: socks4 connect over TCP/IPv4" TEST="$NAME: socks4 connect over TCP/IPv4"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! testaddrs socks4 >/dev/null; then elif ! testaddrs socks4 >/dev/null; then
@ -4226,7 +4195,7 @@ N=$((N+1))
NAME=SOCKS4ACONNECT_TCP4 NAME=SOCKS4ACONNECT_TCP4
case "$TESTS" in case "$TESTS" in
*%functions%*|*%socks%*|*%socks4a%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) *%functions%*|*%chain%*|*%socks%*|*%socks4a%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
TEST="$NAME: socks4a connect over TCP/IPv4" TEST="$NAME: socks4a connect over TCP/IPv4"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! testaddrs socks4a >/dev/null; then elif ! testaddrs socks4a >/dev/null; then
@ -4316,7 +4285,7 @@ N=$((N+1))
NAME=PROXYCONNECT_TCP4 NAME=PROXYCONNECT_TCP4
case "$TESTS" in case "$TESTS" in
*%functions%*|*%proxyconnect%*|*%proxy%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) *%functions%*|*%chain%*|*%proxyconnect%*|*%proxy%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
TEST="$NAME: proxy connect over TCP/IPv4" TEST="$NAME: proxy connect over TCP/IPv4"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! testaddrs proxy >/dev/null; then elif ! testaddrs proxy >/dev/null; then
@ -4592,7 +4561,7 @@ N=$((N+1))
NAME=PROXY2SPACES NAME=PROXY2SPACES
case "$TESTS" in case "$TESTS" in
*%functions%*|*%proxy%*|*%$NAME%*) *%functions%*|*%chain%*|*%proxy%*|*%$NAME%*)
TEST="$NAME: proxy connect accepts status with multiple spaces" TEST="$NAME: proxy connect accepts status with multiple spaces"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! testaddrs proxy >/dev/null; then elif ! testaddrs proxy >/dev/null; then
@ -4888,7 +4857,7 @@ N=$((N+1))
#! #!
NAME=OUTBOUNDIN NAME=OUTBOUNDIN
case "$TESTS" in case "$TESTS" in
*%functions%*|*%proxy%*|*%$NAME%*) *%functions%*|*%chain%*|*%proxy%*|*%$NAME%*)
TEST="$NAME: gender changer via SSL through HTTP proxy, oneshot" TEST="$NAME: gender changer via SSL through HTTP proxy, oneshot"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! feat=$(testaddrs openssl proxy); then elif ! feat=$(testaddrs openssl proxy); then
@ -4975,7 +4944,7 @@ PORT=$((RANDOM+16184))
#! #!
NAME=INTRANETRIPPER NAME=INTRANETRIPPER
case "$TESTS" in case "$TESTS" in
*%functions%*|*%proxy%*|*%$NAME%*) *%functions%*|*%chain%*|*%proxy%*|*%$NAME%*)
TEST="$NAME: gender changer via SSL through HTTP proxy, daemons" TEST="$NAME: gender changer via SSL through HTTP proxy, daemons"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! feat=$(testaddrs openssl proxy); then elif ! feat=$(testaddrs openssl proxy); then
@ -5940,7 +5909,7 @@ N=$((N+1))
NAME=OPENSSLLISTENDSA NAME=OPENSSLLISTENDSA
case "$TESTS" in case "$TESTS" in
*%functions%*|*%$NAME%*) *%functions%*|*%chain%*|*%openssl%*|*%tcp%*|*%$NAME%*)
TEST="$NAME: openssl listen with DSA certificate" TEST="$NAME: openssl listen with DSA certificate"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! testaddrs openssl >/dev/null; then elif ! testaddrs openssl >/dev/null; then
@ -7658,7 +7627,7 @@ TEST="$NAME: end-close keeps EXEC child running"
# data; each client is handled in a sub process with a clone of the forwarder # data; each client is handled in a sub process with a clone of the forwarder
# socket. # socket.
# two client processes connect and send data. normally, the "common" connection # two client processes connect and send data. normally, the "common" connection
# the the cat sub process would terminate when the first client disconnects; # to 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 # with the shut-none option, the data of the second process also has to arrive
# at the target service. # at the target service.
if ! eval $NUMCOND; then :; else if ! eval $NUMCOND; then :; else
@ -10114,13 +10083,14 @@ printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" & $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
waitsctp6port $tsl 1 waitsctp6port $tsl 1
# SCTP does not seem to support half close, so we let it 1s to finish # SCTP does not seem to support half close, so we give it 1s to finish
(echo "$da"; sleep 1) |$CMD2 >>"$tf" 2>>"${te}2" (echo "$da"; sleep 1) |$CMD2 >>"$tf" 2>>"${te}2"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n" $PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD1 &" echo "$CMD1 &"
cat "${te}1"
echo "$CMD2" echo "$CMD2"
cat "$te" cat "${te}2"
numFAIL=$((numFAIL+1)) numFAIL=$((numFAIL+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED: diff:\n" $PRINTF "$FAILED: diff:\n"
@ -10147,7 +10117,7 @@ pf="$(echo $PF |tr A-Z a-z)"
proto="$(echo $KEYW |tr A-Z a-z)" proto="$(echo $KEYW |tr A-Z a-z)"
NAME=OPENSSL_${KEYW}_FORK NAME=OPENSSL_${KEYW}_FORK
case "$TESTS" in case "$TESTS" in
*%functions%*|*%openssl%*|*%sctp%*|*%$pf%*|*%$NAME%*) *%functions%*|*%chain%*|*%openssl%*|*%sctp%*|*%$pf%*|*%$NAME%*)
TEST="$NAME: openssl over SCTP with server fork" TEST="$NAME: openssl over SCTP with server fork"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! testaddrs openssl >/dev/null; then elif ! testaddrs openssl >/dev/null; then
@ -10198,6 +10168,228 @@ SCTP6 IP6 [::1]
" "
# tests with inter address exec (`exec2')
while read c commname
do
if [ -z "$c" ] || [[ "$c" == \#* ]]; then continue; fi
COMMNAME="$(echo $commname |tr 'a-z ' 'A-Z_')"
#
for exec in exec system; do
EXEC="$(echo $exec |tr 'a-z' 'A-Z')"
#
NAME=${EXEC}2_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}2%*|*%$NAME%*)
TEST="$NAME: bidirectional $exec in simple chain ($commname)"
testecho "$N" "$TEST" "STDIO" "$EXEC:bin/cat2.sh|PIPE" "$opts -c$c" "$val_t"
esac
N=$((N+1))
NAME=${EXEC}2UNI_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%{exec}2%*|*%$NAME%*)
TEST="$NAME: unidirectional $exec in simple chain ($commname)"
testecho "$N" "$TEST" "STDIO" "$EXEC:bin/cat2.sh|STDIO" "$opts -u -c$c" "$val_t"
esac
N=$((N+1))
NAME=${EXEC}2CHAIN_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}2%*|*%$NAME%*)
TEST="$NAME: $exec in chain with endpoint $exec ($commname)"
testecho "$N" "$TEST" "STDIO" "$EXEC:bin/predialog.sh|$EXEC:./proxyecho.sh" "$opts -c$c" "$val_t"
esac
N=$((N+1))
NAME=${EXEC}1BI_FORWARD_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}1%*|*%$NAME%*)
TEST="$NAME: ${exec}1 in birectional chain, forward ($commname)"
testecho "$N" "$TEST" "STDIO" "${EXEC}1:cat%NOP|PIPE" "$opts -c$c" "$val_t"
esac
N=$((N+1))
NAME=${EXEC}1UNI_FORWARD_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}1%*|*%$NAME%*)
TEST="$NAME: ${exec}1 in unrectional chain, forward ($commname)"
testecho "$N" "$TEST" "STDIN" "${EXEC}1:cat|STDOUT" "$opts -u -c$c" "$val_t"
esac
N=$((N+1))
NAME=${EXEC}1UNI_BACKWARD_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}1%*|*%$NAME%*)
TEST="$NAME: ${exec}1 in unrectional chain, backward ($commname)"
testecho "$N" "$TEST" "STDOUT" "^${EXEC}1:cat|STDIN" "$opts -U -c$c" "$val_t"
esac
N=$((N+1))
case "$commname" in
"ptys") ;;
*)
NAME=${EXEC}1BI_FORWARD_HALFCLOSE_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}1%*|*%$NAME%*)
TEST="$NAME: ${exec}1 in birectional chain, forward ($commname)"
testod "$N" "$TEST" "STDIO" "${EXEC}1:$OD_C%NOP|PIPE" "$opts -c$c" "$val_t"
esac
N=$((N+1))
;;
esac
case "$commname" in
"ptys") ;;
*)
NAME=${EXEC}1UNI_FORWARD_HALFCLOSE_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}1%*|*%$NAME%*)
TEST="$NAME: ${exec}1 in unrectional chain, forward ($commname)"
testod "$N" "$TEST" "STDIN" "${EXEC}1:$OD_C|STDOUT" "$opts -u -c$c" "$val_t"
esac
N=$((N+1))
;;
esac
case "$commname" in
"ptys") ;;
*)
NAME=${EXEC}1UNI_BACKWARD_HALFCLOSE_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}1%*|*%$NAME%*)
TEST="$NAME: ${exec}1 in unrectional chain, backward ($commname)"
testod "$N" "$TEST" "STDOUT" "^${EXEC}1:$OD_C|STDIN" "$opts -U -c$c" "$val_t"
esac
N=$((N+1))
;;
esac
if [ "$commname" != "pipes" ]; then
NAME=${EXEC}2REV_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}2%*|*%$NAME%*)
TEST="$NAME: bidirectional reverse $exec in simple chain ($commname)"
testecho "$N" "$TEST" "STDIO" "^$EXEC:bin/cat2.sh|PIPE" "$opts -c$c" "$val_t"
esac
N=$((N+1))
fi # ! pipes
if [ "$commname" != "pipes" ]; then
NAME=${EXEC}2UNIREV_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}2%*|*%$NAME%*)
TEST="$NAME: unidirectional reverse $exec in simple chain ($commname)"
testecho "$N" "$TEST" "STDIO" "^$EXEC:bin/cat2.sh|STDIO" "$opts -u -c$c" "$val_t"
esac
N=$((N+1))
fi # ! pipes
case "$commname" in
"pipes") ;;
"ptys") ;;
*)
NAME=${EXEC}2DUAL_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}2%*|*%$NAME%*)
TEST="$NAME: dual $exec in simple chain ($commname)"
testecho "$N" "$TEST" "STDIO" "$EXEC:bin/cat2.sh%$EXEC:bin/cat2.sh|PIPE" "$opts -c$c"
esac
N=$((N+1))
;;
esac
case "$commname" in
"pipes") ;;
"ptys") ;;
*)
NAME=${EXEC}1BI_BACKWARD_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}1%*|*%$NAME%*)
TEST="$NAME: ${exec}1 in birectional chain, backward ($commname)"
testecho "$N" "$TEST" "STDIO" "NOP%${EXEC}1:cat|PIPE" "$opts -c$c" "$val_t"
esac
N=$((N+1))
;;
esac
done # for EXEC in EXEC SYSTEM
# we are still in the commname loop
# here are tests that do not work with SYSTEM
for exec in exec; do
EXEC="$(echo $exec |tr 'a-z' 'A-Z')"
#
case "$commname" in
"ptys") ;;
*)
NAME=${EXEC}1BI_BACKWARD_HALFCLOSE_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}1%*|*%$NAME%*)
TEST="$NAME: ${exec}1 in birectional chain, backward ($commname)"
testod "$N" "$TEST" "STDIO" "NOP%${EXEC}1:$OD_C|PIPE" "$opts -c$c" "$val_t"
esac
N=$((N+1))
;;
esac
case "$commname" in
"ptys") ;;
*)
# currently failes with socketpair, tcp when cat is used because dual mode with
# single fd communication has an implicit half close problem
NAME=${EXEC}1BI_CAT_OD_HALFCLOSE_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}1%*|*%$NAME%*)
TEST="$NAME: ${exec}1 in birectional chain, both directions ($commname)"
testod "$N" "$TEST" "STDIO" "${EXEC}1:$SOCAT -u - -%${EXEC}1:$OD_C|PIPE" "$opts -c$c" "$val_t"
esac
N=$((N+1))
;;
esac
NAME=${EXEC}1BI_BOTH_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}1%*|*%$NAME%*)
TEST="$NAME: ${exec}1 in birectional chain, both directions ($commname)"
testecho "$N" "$TEST" "STDIO" "${EXEC}1:cat%${EXEC}1:cat|PIPE" "$opts -c$c" "$val_t"
esac
N=$((N+1))
case "$commname" in
"ptys") ;;
*)
NAME=${EXEC}1BI_OD_CAT_HALFCLOSE_$COMMNAME
case "$TESTS" in
*%functions%*|*%chain%*|*%$exec%*|*%${exec}1%*|*%$NAME%*)
TEST="$NAME: ${exec}1 in birectional chain, both directions ($commname)"
testod "$N" "$TEST" "STDIO" "${EXEC}1:$OD_C%${EXEC}1:cat|PIPE" "$opts -c$c" "$val_t"
esac
N=$((N+1))
;;
esac
done # for EXEC in EXEC SYSTEM
done <<<"
S two socketpairs
p pipes
s socketpair
Y ptys
t TCP
"
#c=S
#commname=socketpairs
# -u exec1
# -U exec1
echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed" echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed"
if [ "$numFAIL" -gt 0 ]; then if [ "$numFAIL" -gt 0 ]; then

View file

@ -1,5 +1,5 @@
/* source: xio-creat.c */ /* source: xio-creat.c */
/* Copyright Gerhard Rieger 2001-2007 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of create type */ /* this file contains the source for opening addresses of create type */
@ -40,41 +40,42 @@ static int _xioopen_creat(const char *path, int rw, struct opt *opts) {
} }
static int xioopen_creat(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) { static int xioopen_creat(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) {
const char *filename = argv[1]; const char *filename = argv[1];
int rw = (xioflags&XIO_ACCMODE); int rw = (xioflags&XIO_ACCMODE);
int fd;
bool exists; bool exists;
bool opt_unlink_close = false; bool opt_unlink_close = false;
int result; int result;
/* remove old file, or set user/permissions on old file; parse options */ /* remove old file, or set user/permissions on old file; parse options */
if ((result = _xioopen_named_early(argc, argv, fd, groups, &exists, opts)) < 0) { if ((result = _xioopen_named_early(argc, argv, xfd, groups, &exists, opts)) < 0) {
return result; return result;
} }
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (opt_unlink_close) { if (opt_unlink_close) {
if ((fd->stream.unlink_close = strdup(filename)) == NULL) { if ((xfd->stream.unlink_close = strdup(filename)) == NULL) {
Error1("strdup(\"%s\"): out of memory", filename); Error1("strdup(\"%s\"): out of memory", filename);
} }
fd->stream.opt_unlink_close = true; xfd->stream.opt_unlink_close = true;
} }
Notice2("creating regular file \"%s\" for %s", filename, ddirection[rw]); Notice2("creating regular file \"%s\" for %s", filename, ddirection[rw]);
if ((result = _xioopen_creat(filename, rw, opts)) < 0) if ((fd = _xioopen_creat(filename, rw, opts)) < 0)
return result; return fd;
fd->stream.fd1 = fd->stream.fd2 = result; if (XIOWITHRD(rw)) xfd->stream.rfd = fd;
fd->stream.fdtype = FDTYPE_SINGLE; if (XIOWITHWR(rw)) xfd->stream.wfd = fd;
applyopts_named(filename, opts, PH_PASTOPEN); applyopts_named(filename, opts, PH_PASTOPEN);
if ((result = applyopts2(fd->stream.fd1, opts, PH_PASTOPEN, PH_LATE2)) < 0) if ((result = applyopts2(fd, opts, PH_PASTOPEN, PH_LATE2)) < 0)
return result; return result;
applyopts_cloexec(fd->stream.fd1, opts); applyopts_cloexec(fd, opts);
applyopts_fchown(fd->stream.fd1, opts); applyopts_fchown(fd, opts);
if ((result = _xio_openlate(&fd->stream, opts)) < 0) if ((result = _xio_openlate(&xfd->stream, opts)) < 0)
return result; return result;
return 0; return 0;

View file

@ -1,5 +1,5 @@
/* source: xio-exec.c */ /* source: xio-exec.c */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of exec type */ /* this file contains the source for opening addresses of exec type */
@ -16,29 +16,49 @@
#if WITH_EXEC #if WITH_EXEC
static int xioopen_exec1end(int argc, const char *argv[], struct opt *opts, static int xioopen_exec1(int argc, const char *argv[], struct opt *opts,
int xioflags, /* XIO_RDONLY etc. */ int xioflags, /* XIO_RDONLY etc. */
xiofile_t *fd, xiofile_t *fd,
unsigned groups, unsigned groups,
int dummy1, int dummy2, int dummy3 int inter, int form, int dummy3
); );
/* the endpoint variant: get stdin and/or stdout on "left" side. socat does not
provide a "right" side for script */
static const struct xioaddr_endpoint_desc xioendpoint_exec1 = { 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_exec1, false, 0, 0 HELP(":<command-line>") };
/* the inter address variant: the bidirectional form has stdin and stdout on
its "left" side, and FDs 3 (for reading) and FD 4 (for writing) on its right
side. */
static const struct xioaddr_inter_desc xiointer_exec1_2rw = { XIOADDR_INTER, "exec", 1, XIOBIT_RDWR, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_exec1, true, 2, 0, XIOBIT_RDWR HELP(":<command-line>") };
static const struct xioaddr_inter_desc xiointer_exec1_2ro = { XIOADDR_INTER, "exec", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_exec1, true, 2, 0, XIOBIT_WRONLY HELP(":<command-line>") };
static const struct xioaddr_inter_desc xiointer_exec1_2wo = { XIOADDR_INTER, "exec", 1, XIOBIT_WRONLY, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_exec1, true, 2, 0, XIOBIT_RDONLY HELP(":<command-line>") };
/* the unidirectional inter address variant: the "left" side reads from stdin,
and the right side reads from stdout. */
static const struct xioaddr_inter_desc xiointer_exec1_1wo = { XIOADDR_INTER, "exec1", 1, XIOBIT_WRONLY, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_exec1, true, 1, 0, XIOBIT_RDONLY HELP(":<command-line>") };
static const struct xioaddr_endpoint_desc xioaddr_exec1end = { XIOADDR_ENDPOINT, "exec", 1, XIOBIT_ALL, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_exec1end, 0, 0, 0 HELP(":<command-line>") }; /* the general forms, designed for bidirectional transfer (stdio -- 3,4) */
const union xioaddr_desc *xioaddrs_exec[] = { const union xioaddr_desc *xioaddrs_exec[] = {
(union xioaddr_desc *)&xioaddr_exec1end, (union xioaddr_desc *)&xioendpoint_exec1,
(union xioaddr_desc *)&xiointer_exec1_2ro,
(union xioaddr_desc *)&xiointer_exec1_2wo,
(union xioaddr_desc *)&xiointer_exec1_2rw,
NULL };
/* unidirectional inter address (stdin -- stdout) */
const union xioaddr_desc *xioaddrs_exec1[] = {
(union xioaddr_desc *)&xiointer_exec1_1wo,
NULL }; NULL };
const struct optdesc opt_dash = { "dash", "login", OPT_DASH, GROUP_EXEC, PH_PREEXEC, TYPE_BOOL, OFUNC_SPEC }; const struct optdesc opt_dash = { "dash", "login", OPT_DASH, GROUP_EXEC, PH_PREEXEC, TYPE_BOOL, OFUNC_SPEC };
static int xioopen_exec1end(int argc, const char *argv[], struct opt *opts, /* the "1" in the function name means that it takes one parameter */
static int xioopen_exec1(int argc, const char *argv[], struct opt *opts,
int xioflags, /* XIO_RDONLY, XIO_MAYCHILD etc. */ int xioflags, /* XIO_RDONLY, XIO_MAYCHILD etc. */
xiofile_t *fd, xiofile_t *fd,
unsigned groups, unsigned groups,
int dummy1, int dummy2, int dummy3 int inter, int form, int dummy3
) { ) {
int status; int status;
bool dash = false; bool dash = false;
@ -50,7 +70,7 @@ static int xioopen_exec1end(int argc, const char *argv[], struct opt *opts,
retropt_bool(opts, OPT_DASH, &dash); retropt_bool(opts, OPT_DASH, &dash);
status = _xioopen_foxec_end(xioflags, &fd->stream, groups, &opts, &duptostderr); status = _xioopen_progcall(xioflags, &fd->stream, groups, &opts, &duptostderr, inter, form);
if (status < 0) return status; if (status < 0) return status;
if (status == 0) { /* child */ if (status == 0) { /* child */
const char *ends[] = { " ", NULL }; const char *ends[] = { " ", NULL };

View file

@ -1,11 +1,12 @@
/* source: xio-exec.h */ /* source: xio-exec.h */
/* Copyright Gerhard Rieger 2001-2007 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_exec_h_included #ifndef __xio_exec_h_included
#define __xio_exec_h_included 1 #define __xio_exec_h_included 1
extern const union xioaddr_desc *xioaddrs_exec[]; extern const union xioaddr_desc *xioaddrs_exec[];
extern const union xioaddr_desc *xioaddrs_exec1[];
extern const struct optdesc opt_dash; extern const struct optdesc opt_dash;

View file

@ -1,5 +1,5 @@
/* source: xio-fd.c */ /* source: xio-fd.c */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains common file descriptor related option definitions */ /* this file contains common file descriptor related option definitions */
@ -76,6 +76,8 @@ const struct optdesc opt_cool_write = { "cool-write", "coolwrite", OPT_COOL_WRIT
/* control closing of connections */ /* control closing of connections */
const struct optdesc opt_end_close = { "end-close", "close", OPT_END_CLOSE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoclose, XIOCLOSE_CLOSE }; 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.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 }; 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 };
const struct optdesc opt_shut_down = { "shut-down", NULL, OPT_SHUT_DOWN, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoshut, XIOSHUT_DOWN };
const struct optdesc opt_shut_close= { "shut-close", NULL, OPT_SHUT_CLOSE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoshut, XIOSHUT_CLOSE };
/****** generic ioctl() options ******/ /****** generic ioctl() options ******/
const struct optdesc opt_ioctl_void = { "ioctl-void", "ioctl", OPT_IOCTL_VOID, GROUP_FD, PH_FD, TYPE_INT, OFUNC_IOCTL_GENERIC, 0, 0, 0 }; const struct optdesc opt_ioctl_void = { "ioctl-void", "ioctl", OPT_IOCTL_VOID, GROUP_FD, PH_FD, TYPE_INT, OFUNC_IOCTL_GENERIC, 0, 0, 0 };

View file

@ -43,6 +43,8 @@ extern const struct optdesc opt_f_setlkw_wr;
extern const struct optdesc opt_cool_write; extern const struct optdesc opt_cool_write;
extern const struct optdesc opt_end_close; extern const struct optdesc opt_end_close;
extern const struct optdesc opt_shut_none; extern const struct optdesc opt_shut_none;
extern const struct optdesc opt_shut_down;
extern const struct optdesc opt_shut_close;
extern const struct optdesc opt_streams_i_push; extern const struct optdesc opt_streams_i_push;
#endif /* !defined(__xio_fd_h_included) */ #endif /* !defined(__xio_fd_h_included) */

View file

@ -15,8 +15,8 @@
static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts, int rw, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3); static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts, int rw, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3);
const struct xioaddr_endpoint_desc xioaddr_fdnum1 = { XIOADDR_ENDPOINT, "fd", 1, XIOBIT_ALL, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_fdnum, 0, 0, 0 HELP(":<num>") }; const struct xioaddr_endpoint_desc xioaddr_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_UNSPEC, XIOCLOSE_CLOSE, xioopen_fdnum, 0, 0, 0 HELP(":<num>") };
const struct xioaddr_endpoint_desc xioaddr_fdnum2 = { XIOADDR_ENDPOINT, "fd", 2, XIOBIT_RDWR, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_fdnum, 0, 0, 0 HELP(":<numout>:<numin>") }; const 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_UNSPEC, XIOCLOSE_CLOSE, xioopen_fdnum, 0, 0, 0 HELP(":<numout>:<numin>") };
const union xioaddr_desc *xioaddrs_fdnum[] = { const union xioaddr_desc *xioaddrs_fdnum[] = {
(union xioaddr_desc *)&xioaddr_fdnum1, (union xioaddr_desc *)&xioaddr_fdnum1,
@ -30,6 +30,7 @@ static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts,
char *a1; char *a1;
int rw = (xioflags&XIO_ACCMODE); int rw = (xioflags&XIO_ACCMODE);
int numfd1, numfd2 = -1; int numfd1, numfd2 = -1;
int numrfd, numwfd;
int result; int result;
if (argc < 2 || argc > 3) { if (argc < 2 || argc > 3) {
@ -49,23 +50,32 @@ static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts,
if (rw != XIO_RDWR) { if (rw != XIO_RDWR) {
Warn("two file descriptors given for unidirectional transfer"); Warn("two file descriptors given for unidirectional transfer");
} }
numfd2 = numfd1; numwfd = numfd1;
numfd1 = strtoul(argv[2], &a1, 0); numrfd = strtoul(argv[2], &a1, 0);
if (*a1 != '\0') { if (*a1 != '\0') {
Error1("error in FD number \"%s\"", argv[2]); Error1("error in FD number \"%s\"", argv[2]);
} }
/* we dont want to see these fds in child processes */ /* we dont want to see these fds in child processes */
if (Fcntl_l(numfd2, F_SETFD, FD_CLOEXEC) < 0) { if (Fcntl_l(numrfd, F_SETFD, FD_CLOEXEC) < 0) {
Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", numfd2, strerror(errno)); Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", numrfd, strerror(errno));
}
} else {
if (XIOWITHWR(rw)) {
numwfd = numfd1;
numrfd = -1;
} else {
numrfd = numfd1;
numwfd = -1;
} }
} }
if (argv[2] == NULL) { if (argv[2] == NULL) {
Notice2("using file descriptor %d for %s", numfd1, ddirection[rw]); Notice2("using file descriptor %d for %s",
numrfd>=0?numrfd:numwfd, ddirection[rw]);
} else { } else {
Notice4("using file descriptors %d for %s and %d for %s", numfd1, ddirection[((rw+1)&1)-1], numfd2, ddirection[((rw+1)&2)-1]); Notice4("using file descriptors %d for %s and %d for %s", numrfd, ddirection[((rw+1)&1)-1], numwfd, ddirection[((rw+1)&2)-1]);
} }
if ((result = xioopen_fd(opts, rw, xfd, numfd1, numfd2, dummy2, dummy3)) < 0) { if ((result = xioopen_fd(opts, rw, xfd, numrfd, numwfd, dummy2, dummy3)) < 0) {
return result; return result;
} }
return 0; return 0;
@ -77,21 +87,35 @@ static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts,
/* retrieve and apply options to a standard file descriptor. /* retrieve and apply options to a standard file descriptor.
Do not set FD_CLOEXEC flag. */ Do not set FD_CLOEXEC flag. */
int xioopen_fd(struct opt *opts, int rw, xiofile_t *xfd, int numfd1, int numfd2, int dummy2, int dummy3) { int xioopen_fd(struct opt *opts, int rw, xiofile_t *xfd, int numrfd, int numwfd, int dummy2, int dummy3) {
int fd;
struct stat buf;
xfd->stream.fd1 = numfd1; if (numwfd >= 0) {
xfd->stream.fd2 = numfd2; if (Fstat(numwfd, &buf) < 0) {
if (numfd2 >= 0) { Warn2("fstat(%d, ): %s", numwfd, strerror(errno));
xfd->stream.fdtype = FDTYPE_DOUBLE; }
if ((buf.st_mode&S_IFMT) == S_IFSOCK &&
xfd->stream.howtoshut == XIOSHUT_UNSPEC) {
xfd->stream.howtoshut = XIOSHUT_DOWN;
}
}
if (xfd->stream.howtoshut == XIOSHUT_UNSPEC)
xfd->stream.howtoshut = XIOSHUT_CLOSE;
xfd->stream.rfd = numrfd;
xfd->stream.wfd = numwfd;
if (numrfd >= 0) {
fd = numrfd;
} else { } else {
xfd->stream.fdtype = FDTYPE_SINGLE; fd = numwfd;
} }
#if WITH_TERMIOS #if WITH_TERMIOS
if (Isatty(xfd->stream.fd1)) { if (Isatty(fd)) {
if (Tcgetattr(xfd->stream.fd1, &xfd->stream.savetty) < 0) { if (Tcgetattr(fd, &xfd->stream.savetty) < 0) {
Warn2("cannot query current terminal settings on fd %d: %s", Warn2("cannot query current terminal settings on fd %d: %s",
xfd->stream.fd1, strerror(errno)); fd, strerror(errno));
} else { } else {
xfd->stream.ttyvalid = true; xfd->stream.ttyvalid = true;
} }
@ -100,7 +124,7 @@ int xioopen_fd(struct opt *opts, int rw, xiofile_t *xfd, int numfd1, int numfd2,
if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1; if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
applyopts2(xfd->stream.fd1, opts, PH_INIT, PH_FD); applyopts2(fd, opts, PH_INIT, PH_FD);
return _xio_openlate(&xfd->stream, opts); return _xio_openlate(&xfd->stream, opts);
} }

View file

@ -76,51 +76,52 @@ const union xioaddr_desc *xioaddrs_open[] = {
if the filesystem entry already exists, the data is appended if the filesystem entry already exists, the data is appended
if it does not exist, a file is created and the data is appended if it does not exist, a file is created and the data is appended
*/ */
static int xioopen_open1(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 *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) {
const char *filename = argv[1]; const char *filename = argv[1];
int rw = (xioflags & XIO_ACCMODE); int rw = (xioflags & XIO_ACCMODE);
int fd;
bool exists; bool exists;
bool opt_unlink_close = false; bool opt_unlink_close = false;
int result; int result;
/* remove old file, or set user/permissions on old file; parse options */ /* remove old file, or set user/permissions on old file; parse options */
if ((result = _xioopen_named_early(argc, argv, fd, groups, &exists, opts)) < 0) { if ((result = _xioopen_named_early(argc, argv, xfd, groups, &exists, opts)) < 0) {
return result; return result;
} }
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (opt_unlink_close) { if (opt_unlink_close) {
if ((fd->stream.unlink_close = strdup(filename)) == NULL) { if ((xfd->stream.unlink_close = strdup(filename)) == NULL) {
Error1("strdup(\"%s\"): out of memory", filename); Error1("strdup(\"%s\"): out of memory", filename);
} }
fd->stream.opt_unlink_close = true; xfd->stream.opt_unlink_close = true;
} }
Notice3("opening %s \"%s\" for %s", Notice3("opening %s \"%s\" for %s",
filetypenames[(result&S_IFMT)>>12], filename, ddirection[rw]); filetypenames[(result&S_IFMT)>>12], filename, ddirection[rw]);
if ((result = _xioopen_open(filename, rw, opts)) < 0) if ((fd = _xioopen_open(filename, rw, opts)) < 0)
return result; return fd;
fd->stream.fd1 = result; if (XIOWITHRD(rw)) xfd->stream.rfd = fd;
fd->stream.fdtype = FDTYPE_SINGLE; if (XIOWITHWR(rw)) xfd->stream.wfd = fd;
#if WITH_TERMIOS #if WITH_TERMIOS
if (Isatty(fd->stream.fd1)) { if (Isatty(fd)) {
if (Tcgetattr(fd->stream.fd1, &fd->stream.savetty) < 0) { if (Tcgetattr(fd, &xfd->stream.savetty) < 0) {
Warn2("cannot query current terminal settings on fd %d: %s", Warn2("cannot query current terminal settings on fd %d: %s",
fd->stream.fd1, strerror(errno)); fd, strerror(errno));
} else { } else {
fd->stream.ttyvalid = true; xfd->stream.ttyvalid = true;
} }
} }
#endif /* WITH_TERMIOS */ #endif /* WITH_TERMIOS */
applyopts_named(filename, opts, PH_FD); applyopts_named(filename, opts, PH_FD);
applyopts(fd->stream.fd1, opts, PH_FD); applyopts(fd, opts, PH_FD);
applyopts_cloexec(fd->stream.fd1, opts); applyopts_cloexec(fd, opts);
applyopts_fchown(fd->stream.fd1, opts); applyopts_fchown(fd, opts);
if ((result = _xio_openlate(&fd->stream, opts)) < 0) if ((result = _xio_openlate(&xfd->stream, opts)) < 0)
return result; return result;
return 0; return 0;

View file

@ -14,7 +14,7 @@
#if WITH_GOPEN #if WITH_GOPEN
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); static int xioopen_gopen1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3);
const struct xioaddr_endpoint_desc xioaddr_gopen1 = { XIOADDR_SYS, "gopen", 1, XIOBIT_ALL, GROUP_FD|GROUP_FIFO|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS|GROUP_SOCKET|GROUP_SOCK_UNIX, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_gopen1, 0, 0, 0 HELP(":<filename>") }; const struct xioaddr_endpoint_desc xioaddr_gopen1 = { XIOADDR_SYS, "gopen", 1, XIOBIT_ALL, GROUP_FD|GROUP_FIFO|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS|GROUP_SOCKET|GROUP_SOCK_UNIX, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_gopen1, 0, 0, 0 HELP(":<filename>") };
@ -24,8 +24,10 @@ const union xioaddr_desc *xioaddrs_gopen[] = {
NULL 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) { static int xioopen_gopen1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) {
const char *filename = argv[1]; const char *filename = argv[1];
int fd;
int rw = (xioflags & XIO_ACCMODE);
flags_t openflags = (xioflags & XIO_ACCMODE); flags_t openflags = (xioflags & XIO_ACCMODE);
mode_t st_mode; mode_t st_mode;
bool exists; bool exists;
@ -33,7 +35,7 @@ static int xioopen_gopen1(int argc, const char *argv[], struct opt *opts, int xi
int result; int result;
if ((result = if ((result =
_xioopen_named_early(argc, argv, fd, GROUP_NAMED|groups, &exists, opts)) < 0) { _xioopen_named_early(argc, argv, xfd, GROUP_NAMED|groups, &exists, opts)) < 0) {
return result; return result;
} }
st_mode = result; st_mode = result;
@ -56,18 +58,24 @@ static int xioopen_gopen1(int argc, const char *argv[], struct opt *opts, int xi
Info1("\"%s\" is a socket, connecting to it", filename); Info1("\"%s\" is a socket, connecting to it", filename);
fd->stream.howtoshut = XIOSHUT_DOWN; xfd->stream.howtoshut = XIOSHUT_DOWN;
fd->stream.howtoclose = XIOCLOSE_CLOSE; xfd->stream.howtoclose = XIOCLOSE_CLOSE;
result = result =
_xioopen_unix_client(&fd->stream, xioflags, groups, 0, opts, filename); _xioopen_unix_client(&xfd->stream, xioflags, groups, 0, opts, filename);
if (result < 0) { if (result < 0) {
return result; return result;
} }
if (xfd->stream.rfd >= 0) {
fd = xfd->stream.rfd;
} else {
fd = xfd->stream.wfd;
}
applyopts_named(filename, opts, PH_PASTOPEN); /* unlink-late */ applyopts_named(filename, opts, PH_PASTOPEN); /* unlink-late */
if (Getsockname(fd->stream.fd1, (struct sockaddr *)&us, &uslen) < 0) { if (Getsockname(fd, (struct sockaddr *)&us, &uslen) < 0) {
Warn4("getsockname(%d, %p, {%d}): %s", Warn4("getsockname(%d, %p, {%d}): %s",
fd->stream.fd1, &us, uslen, strerror(errno)); fd, &us, uslen, strerror(errno));
} else { } else {
Notice1("successfully connected via %s", Notice1("successfully connected via %s",
sockaddr_unix_info(&us.un, uslen, sockaddr_unix_info(&us.un, uslen,
@ -85,20 +93,20 @@ static int xioopen_gopen1(int argc, const char *argv[], struct opt *opts, int xi
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (opt_unlink_close) { if (opt_unlink_close) {
if ((fd->stream.unlink_close = strdup(filename)) == NULL) { if ((xfd->stream.unlink_close = strdup(filename)) == NULL) {
Error1("strdup(\"%s\"): out of memory", filename); Error1("strdup(\"%s\"): out of memory", filename);
} }
fd->stream.opt_unlink_close = true; xfd->stream.opt_unlink_close = true;
} }
if (fd->stream.howtoshut == XIOSHUT_UNSPEC) if (xfd->stream.howtoshut == XIOSHUT_UNSPEC)
fd->stream.howtoshut = XIOSHUT_NONE; xfd->stream.howtoshut = XIOSHUT_NONE;
if (fd->stream.howtoclose == XIOCLOSE_UNSPEC) if (xfd->stream.howtoclose == XIOCLOSE_UNSPEC)
fd->stream.howtoclose = XIOCLOSE_CLOSE; xfd->stream.howtoclose = XIOCLOSE_CLOSE;
Notice3("opening %s \"%s\" for %s", Notice3("opening %s \"%s\" for %s",
filetypenames[(st_mode&S_IFMT)>>12], filename, ddirection[(xioflags&XIO_ACCMODE)]); filetypenames[(st_mode&S_IFMT)>>12], filename, ddirection[(xioflags&XIO_ACCMODE)]);
if ((result = _xioopen_open(filename, openflags, opts)) < 0) if ((fd = _xioopen_open(filename, openflags, opts)) < 0)
return result; return fd;
#ifdef I_PUSH #ifdef I_PUSH
if (S_ISCHR(st_mode)) { if (S_ISCHR(st_mode)) {
Ioctl(result, I_PUSH, "ptem"); Ioctl(result, I_PUSH, "ptem");
@ -106,28 +114,30 @@ static int xioopen_gopen1(int argc, const char *argv[], struct opt *opts, int xi
Ioctl(result, I_PUSH, "ttcompat"); Ioctl(result, I_PUSH, "ttcompat");
} }
#endif #endif
fd->stream.fd1 = result;
#if WITH_TERMIOS #if WITH_TERMIOS
if (Isatty(fd->stream.fd1)) { if (Isatty(fd)) {
if (Tcgetattr(fd->stream.fd1, &fd->stream.savetty) < 0) { if (Tcgetattr(fd, &xfd->stream.savetty) < 0) {
Warn2("cannot query current terminal settings on fd %d: %s", Warn2("cannot query current terminal settings on fd %d: %s",
fd->stream.fd1, strerror(errno)); fd, strerror(errno));
} else { } else {
fd->stream.ttyvalid = true; xfd->stream.ttyvalid = true;
} }
} }
#endif /* WITH_TERMIOS */ #endif /* WITH_TERMIOS */
applyopts_named(filename, opts, PH_FD); applyopts_named(filename, opts, PH_FD);
applyopts(fd->stream.fd1, opts, PH_FD); applyopts(fd, opts, PH_FD);
applyopts_cloexec(fd->stream.fd1, opts); applyopts_cloexec(fd, opts);
if (XIOWITHRD(rw)) xfd->stream.rfd = fd;
if (XIOWITHWR(rw)) xfd->stream.wfd = fd;
} }
if ((result = applyopts2(fd->stream.fd1, opts, PH_PASTSOCKET, PH_CONNECTED)) < 0) if ((result = applyopts2(fd, opts, PH_PASTSOCKET, PH_CONNECTED)) < 0)
return result; return result;
if ((result = _xio_openlate(&fd->stream, opts)) < 0) if ((result = _xio_openlate(&xfd->stream, opts)) < 0)
return result; return result;
return 0; return 0;
} }

View file

@ -30,6 +30,7 @@ int _xioopen_interface(const char *ifname,
struct opt *opts, int xioflags, xiofile_t *xxfd, struct opt *opts, int xioflags, xiofile_t *xxfd,
unsigned groups) { unsigned groups) {
xiosingle_t *xfd = &xxfd->stream; xiosingle_t *xfd = &xxfd->stream;
int rw = (xioflags&XIO_ACCMODE);
int pf = PF_PACKET; int pf = PF_PACKET;
union sockaddr_union us = {{0}}; union sockaddr_union us = {{0}};
socklen_t uslen; socklen_t uslen;
@ -38,6 +39,7 @@ int _xioopen_interface(const char *ifname,
bool needbind = false; bool needbind = false;
char *bindstring = NULL; char *bindstring = NULL;
struct sockaddr_ll sall = { 0 }; struct sockaddr_ll sall = { 0 };
int result;
if (ifindex(ifname, &ifidx, -1) < 0) { if (ifindex(ifname, &ifidx, -1) < 0) {
Error1("unknown interface \"%s\"", ifname); Error1("unknown interface \"%s\"", ifname);
@ -70,9 +72,15 @@ int _xioopen_interface(const char *ifname,
needbind = true; needbind = true;
xfd->peersa = (union sockaddr_union)us; xfd->peersa = (union sockaddr_union)us;
return if ((result =
_xioopen_dgram_sendto(needbind?&us:NULL, uslen, _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf, socktype, 0); opts, xioflags, xfd, groups, pf, socktype, 0))
!= STAT_OK) {
return result;
}
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
if (!XIOWITHRD(rw)) xfd->rfd = -1;
return result;
} }
static static

View file

@ -26,6 +26,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
unsigned groups, int socktype, int ipproto, unsigned groups, int socktype, int ipproto,
int pf) { int pf) {
struct single *xfd = &xxfd->stream; struct single *xfd = &xxfd->stream;
int rw = (xioflags & XIO_ACCMODE);
struct opt *opts0 = NULL; struct opt *opts0 = NULL;
const char *hostname = argv[1], *portname = argv[2]; const char *hostname = argv[1], *portname = argv[2];
bool dofork = false; bool dofork = false;
@ -98,6 +99,8 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
default: default:
return result; return result;
} }
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
if (!XIOWITHRD(rw)) xfd->rfd = -1;
#if WITH_RETRY #if WITH_RETRY
if (dofork) { if (dofork) {
@ -121,7 +124,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
/* parent process */ /* parent process */
Notice1("forked off child process "F_pid, pid); Notice1("forked off child process "F_pid, pid);
Close(xfd->fd1); Close(xfd->rfd);
/* with and without retry */ /* with and without retry */
Nanosleep(&xfd->intervall, NULL); Nanosleep(&xfd->intervall, NULL);

View file

@ -110,6 +110,7 @@ int
int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, socklen_t uslen, int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, socklen_t uslen,
struct opt *opts, int pf, int socktype, int proto, int level) { struct opt *opts, int pf, int socktype, int proto, int level) {
struct sockaddr sa; struct sockaddr sa;
int rw = (xioflags&XIO_ACCMODE);
socklen_t salen; socklen_t salen;
int backlog = 5; /* why? 1 seems to cause problems under some load */ int backlog = 5; /* why? 1 seems to cause problems under some load */
char *rangename; char *rangename;
@ -140,22 +141,21 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
xiosetchilddied(); /* set SIGCHLD handler */ xiosetchilddied(); /* set SIGCHLD handler */
} }
if ((xfd->fd1 = xiosocket(opts, us->sa_family, socktype, proto, level)) < 0) { if ((xfd->rfd = xiosocket(opts, us->sa_family, socktype, proto, level)) < 0) {
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
xfd->fdtype = FDTYPE_SINGLE;
applyopts(xfd->fd1, opts, PH_PASTSOCKET); applyopts(xfd->rfd, opts, PH_PASTSOCKET);
applyopts_cloexec(xfd->fd1, opts); applyopts_cloexec(xfd->rfd, opts);
applyopts(xfd->fd1, opts, PH_PREBIND); applyopts(xfd->rfd, opts, PH_PREBIND);
applyopts(xfd->fd1, opts, PH_BIND); applyopts(xfd->rfd, opts, PH_BIND);
if (Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) { if (Bind(xfd->rfd, (struct sockaddr *)us, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1, Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->rfd,
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
strerror(errno)); strerror(errno));
Close(xfd->fd1); Close(xfd->rfd);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -167,12 +167,12 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
/* under some circumstances (e.g., TCP listen on port 0) bind() fills empty /* under some circumstances (e.g., TCP listen on port 0) bind() fills empty
fields that we want to know. */ fields that we want to know. */
salen = sizeof(sa); salen = sizeof(sa);
if (Getsockname(xfd->fd1, us, &uslen) < 0) { if (Getsockname(xfd->rfd, us, &uslen) < 0) {
Warn4("getsockname(%d, %p, {%d}): %s", Warn4("getsockname(%d, %p, {%d}): %s",
xfd->fd1, &us, uslen, strerror(errno)); xfd->rfd, &us, uslen, strerror(errno));
} }
applyopts(xfd->fd1, opts, PH_PASTBIND); applyopts(xfd->rfd, opts, PH_PASTBIND);
#if WITH_UNIX #if WITH_UNIX
if (us->sa_family == AF_UNIX) { if (us->sa_family == AF_UNIX) {
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
@ -182,8 +182,8 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
#endif /* WITH_UNIX */ #endif /* WITH_UNIX */
retropt_int(opts, OPT_BACKLOG, &backlog); retropt_int(opts, OPT_BACKLOG, &backlog);
if (Listen(xfd->fd1, backlog) < 0) { if (Listen(xfd->rfd, backlog) < 0) {
Error3("listen(%d, %d): %s", xfd->fd1, backlog, strerror(errno)); Error3("listen(%d, %d): %s", xfd->rfd, backlog, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -211,8 +211,8 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
#endif /* WITH_TCP || WITH_UDP */ #endif /* WITH_TCP || WITH_UDP */
retropt_int(opts, OPT_BACKLOG, &backlog); retropt_int(opts, OPT_BACKLOG, &backlog);
if (Listen(xfd->fd1, backlog) < 0) { if (Listen(xfd->rfd, backlog) < 0) {
Error3("listen(%d, %d): %s", xfd->fd1, backlog, strerror(errno)); Error3("listen(%d, %d): %s", xfd->rfd, backlog, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -231,7 +231,7 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
do { do {
/*? int level = E_ERROR;*/ /*? int level = E_ERROR;*/
Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname))); Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname)));
ps = Accept(xfd->fd1, (struct sockaddr *)&sa, &salen); ps = Accept(xfd->rfd, (struct sockaddr *)&sa, &salen);
if (ps >= 0) { if (ps >= 0) {
/*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", xfd->fd1, &sa, salen, ps);*/ /*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", xfd->fd1, &sa, salen, ps);*/
break; /* success, break out of loop */ break; /* success, break out of loop */
@ -241,12 +241,12 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
} }
if (errno == ECONNABORTED) { if (errno == ECONNABORTED) {
Notice4("accept(%d, %p, {"F_Zu"}): %s", Notice4("accept(%d, %p, {"F_Zu"}): %s",
xfd->fd1, &sa, salen, strerror(errno)); xfd->rfd, &sa, salen, strerror(errno));
continue; continue;
} }
Msg4(level, "accept(%d, %p, {"F_Zu"}): %s", Msg4(level, "accept(%d, %p, {"F_Zu"}): %s",
xfd->fd1, &sa, salen, strerror(errno)); xfd->rfd, &sa, salen, strerror(errno));
Close(xfd->fd1); Close(xfd->rfd);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} while (true); } while (true);
applyopts_cloexec(ps, opts); applyopts_cloexec(ps, opts);
@ -275,13 +275,13 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
sockaddr_info((struct sockaddr *)pa, pas, sockaddr_info((struct sockaddr *)pa, pas,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
applyopts(xfd->fd1, opts, PH_FD); applyopts(xfd->rfd, opts, PH_FD);
applyopts(xfd->fd1, opts, PH_CONNECTED); applyopts(xfd->rfd, opts, PH_CONNECTED);
if (dofork) { if (dofork) {
pid_t pid; /* mostly int; only used with fork */ pid_t pid; /* mostly int; only used with fork */
if ((pid = xio_fork(false, level==E_ERROR?level:E_WARN)) < 0) { if ((pid = xio_fork(false, level==E_ERROR?level:E_WARN)) < 0) {
Close(xfd->fd1); Close(xfd->rfd);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
if (pid == 0) { /* child */ if (pid == 0) { /* child */
@ -290,10 +290,11 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
Info1("just born: client process "F_pid, cpid); Info1("just born: client process "F_pid, cpid);
xiosetenvulong("PID", cpid, 1); xiosetenvulong("PID", cpid, 1);
if (Close(xfd->fd1) < 0) { if (Close(xfd->rfd) < 0) {
Info2("close(%d): %s", xfd->fd1, strerror(errno)); Info2("close(%d): %s", xfd->rfd, strerror(errno));
} }
xfd->fd1 = ps; if (XIOWITHRD(rw)) xfd->rfd = ps;
if (XIOWITHWR(rw)) xfd->wfd = ps;
#if WITH_RETRY #if WITH_RETRY
/* !? */ /* !? */
@ -318,10 +319,11 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
} }
Info("still listening"); Info("still listening");
} else { } else {
if (Close(xfd->fd1) < 0) { if (Close(xfd->rfd) < 0) {
Info2("close(%d): %s", xfd->fd1, strerror(errno)); Info2("close(%d): %s", xfd->rfd, strerror(errno));
} }
xfd->fd1 = ps; if (XIOWITHRD(rw)) xfd->rfd = ps;
if (XIOWITHWR(rw)) xfd->wfd = ps;
break; break;
} }
} }

View file

@ -40,7 +40,7 @@ static int xioopen_nop(int argc, const char *argv[], struct opt *opts,
return STAT_NORETRY; return STAT_NORETRY;
} }
if (xfd->fd1 < 0 && xfd->fd2 < 0) { if (xfd->rfd < 0 && xfd->wfd < 0) { /*!!!*/
Error("NOP cannot be endpoint"); Error("NOP cannot be endpoint");
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -53,7 +53,7 @@ static int xioopen_nop(int argc, const char *argv[], struct opt *opts,
xfd->dtype = XIODATA_STREAM; xfd->dtype = XIODATA_STREAM;
/*xfd->fdtype = FDTYPE_DOUBLE;*/ /*xfd->fdtype = FDTYPE_DOUBLE;*/
applyopts(xfd->fd1, opts, PH_ALL); applyopts(xfd->rfd, opts, PH_ALL);
if ((result = _xio_openlate(xfd, opts)) < 0) if ((result = _xio_openlate(xfd, opts)) < 0)
return result; return result;

View file

@ -225,6 +225,7 @@ static int
addr_openssl */ addr_openssl */
{ {
struct single *xfd = &xxfd->stream; struct single *xfd = &xxfd->stream;
int rw = (xioflags&XIO_ACCMODE);
struct opt *opts0 = NULL; struct opt *opts0 = NULL;
const char *hostname, *portname = NULL; const char *hostname, *portname = NULL;
int pf = PF_UNSPEC; int pf = PF_UNSPEC;
@ -282,7 +283,7 @@ static int
} else if (argc = 1) { } else if (argc = 1) {
/* or a "non terminal" address without required parameters */ /* or a "non terminal" address without required parameters */
if (xfd->fd2 < 0) { if (xfd->wfd < 0) {
Error("openssl-connect without hostname and port must be an embedded address"); Error("openssl-connect without hostname and port must be an embedded address");
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -347,6 +348,7 @@ static int
default: default:
return result; return result;
} }
xfd->wfd = xfd->rfd;
} }
/*! isn't this too early? */ /*! isn't this too early? */
@ -358,13 +360,12 @@ static int
_xioopen_openssl_connect(xfd, opt_ver, xfd->para.openssl.ctx, level); _xioopen_openssl_connect(xfd, opt_ver, xfd->para.openssl.ctx, level);
switch (result) { switch (result) {
case STAT_OK: break; case STAT_OK: break;
#if WITH_RETRY #if WITH_RETRY
case STAT_RETRYLATER: case STAT_RETRYLATER:
case STAT_RETRYNOW: case STAT_RETRYNOW:
if (xfd->forever || xfd->retry) { if (xfd->forever || xfd->retry) {
Close(xfd->fd1); Close(xfd->rfd);
if (xfd->fdtype == FDTYPE_DOUBLE) Close(xfd->wfd);
Close(xfd->fd2);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
if (result == STAT_RETRYLATER) { if (result == STAT_RETRYLATER) {
Nanosleep(&xfd->intervall, NULL); Nanosleep(&xfd->intervall, NULL);
@ -372,7 +373,7 @@ static int
--xfd->retry; --xfd->retry;
continue; continue;
} }
#endif /* WITH_RETRY */ #endif /* WITH_RETRY */
default: return STAT_NORETRY; default: return STAT_NORETRY;
} }
@ -380,7 +381,7 @@ static int
xiosetchilddied(); /* set SIGCHLD handler */ xiosetchilddied(); /* set SIGCHLD handler */
} }
#if WITH_RETRY #if WITH_RETRY
if (dofork) { if (dofork) {
pid_t pid; pid_t pid;
int level = E_ERROR; int level = E_ERROR;
@ -401,9 +402,8 @@ static int
/* parent process */ /* parent process */
Notice1("forked off child process "F_pid, pid); Notice1("forked off child process "F_pid, pid);
Close(xfd->fd1); Close(xfd->rfd);
if (xfd->fdtype == FDTYPE_DOUBLE) Close(xfd->wfd);
Close(xfd->fd2);
sycSSL_free(xfd->para.openssl.ssl); sycSSL_free(xfd->para.openssl.ssl);
xfd->para.openssl.ssl = NULL; xfd->para.openssl.ssl = NULL;
/* with and without retry */ /* with and without retry */
@ -411,7 +411,7 @@ static int
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
continue; /* with next socket() bind() connect() */ continue; /* with next socket() bind() connect() */
} }
#endif /* WITH_RETRY */ #endif /* WITH_RETRY */
break; break;
} while (true); /* drop out on success */ } while (true); /* drop out on success */
@ -419,14 +419,14 @@ static int
/* fill in the fd structure */ /* fill in the fd structure */
return STAT_OK; return STAT_OK;
} }
/* this function is typically called within the OpenSSL client fork/retry loop. /* this function is typically called within the OpenSSL client fork/retry loop.
xfd must be of type DATA_OPENSSL, and its fd must be set with a valid file xfd must be of type DATA_OPENSSL, and its fd must be set with a valid file
descriptor. this function then performs all SSL related step to make a valid descriptor. this function then performs all SSL related step to make a valid
SSL connection from an FD and a CTX. */ SSL connection from an FD and a CTX. */
int _xioopen_openssl_connect(struct single *xfd, int _xioopen_openssl_connect(struct single *xfd,
bool opt_ver, bool opt_ver,
SSL_CTX *ctx, SSL_CTX *ctx,
int level) { int level) {
@ -542,7 +542,7 @@ static int
} }
} else if (argc == 1) { } else if (argc == 1) {
if (xfd->fd1 < 0) { if (xfd->rfd < 0) {
Error("openssl-listen without port must be an embedded address"); Error("openssl-listen without port must be an embedded address");
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -590,7 +590,6 @@ static int
E_ERROR E_ERROR
#endif /* WITH_RETRY */ #endif /* WITH_RETRY */
); );
}
/*! not sure if we should try again on retry/forever */ /*! not sure if we should try again on retry/forever */
switch (result) { switch (result) {
case STAT_OK: break; case STAT_OK: break;
@ -611,6 +610,8 @@ static int
default: default:
return result; return result;
} }
xfd->wfd = xfd->rfd;
}
result = result =
_xioopen_openssl_listen(xfd, opt_ver, xfd->para.openssl.ctx, level); _xioopen_openssl_listen(xfd, opt_ver, xfd->para.openssl.ctx, level);
switch (result) { switch (result) {
@ -1088,33 +1089,37 @@ static int xioSSL_set_fd(struct single *xfd, int level) {
unsigned long err; unsigned long err;
/* assign a network connection to the SSL object */ /* assign a network connection to the SSL object */
if (xfd->fd2 < 0) { if (xfd->rfd == xfd->wfd) {
if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->fd1) <= 0) { if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->rfd) <= 0) {
Msg(level, "SSL_set_fd() failed"); Msg(level, "SSL_set_fd() failed");
while (err = ERR_get_error()) { while (err = ERR_get_error()) {
Msg2(level, "SSL_set_fd(, %d): %s", Msg2(level, "SSL_set_fd(, %d): %s",
xfd->fd2, ERR_error_string(err, NULL)); xfd->wfd, ERR_error_string(err, NULL));
} }
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} else { } else {
if (sycSSL_set_rfd(xfd->para.openssl.ssl, xfd->fd1) <= 0) { if (xfd->rfd >= 0) {
if (sycSSL_set_rfd(xfd->para.openssl.ssl, xfd->rfd) <= 0) {
Msg(level, "SSL_set_rfd() failed"); Msg(level, "SSL_set_rfd() failed");
while (err = ERR_get_error()) { while (err = ERR_get_error()) {
Msg2(level, "SSL_set_rfd(, %d): %s", Msg2(level, "SSL_set_rfd(, %d): %s",
xfd->fd1, ERR_error_string(err, NULL)); xfd->rfd, ERR_error_string(err, NULL));
} }
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
if (sycSSL_set_wfd(xfd->para.openssl.ssl, xfd->fd2) <= 0) { }
if (xfd->wfd >= 0) {
if (sycSSL_set_wfd(xfd->para.openssl.ssl, xfd->wfd) <= 0) {
Msg(level, "SSL_set_wfd() failed"); Msg(level, "SSL_set_wfd() failed");
while (err = ERR_get_error()) { while (err = ERR_get_error()) {
Msg2(level, "SSL_set_wfd(, %d): %s", Msg2(level, "SSL_set_wfd(, %d): %s",
xfd->fd2, ERR_error_string(err, NULL)); xfd->wfd, ERR_error_string(err, NULL));
} }
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} }
}
return STAT_OK; return STAT_OK;
} }

View file

@ -42,11 +42,10 @@ static int xioopen_fifo0(int argc, const char *argv[], struct opt *opts, int xio
sock->common.tag = XIO_TAG_RDWR; sock->common.tag = XIO_TAG_RDWR;
sock->stream.dtype = XIODATA_2PIPE; sock->stream.dtype = XIODATA_2PIPE;
sock->stream.fd1 = filedes[0]; sock->stream.rfd = filedes[0];
sock->stream.fd2 = filedes[1]; sock->stream.wfd = filedes[1];
sock->stream.fdtype = FDTYPE_DOUBLE; applyopts_cloexec(sock->stream.rfd, opts);
applyopts_cloexec(sock->stream.fd1, opts); applyopts_cloexec(sock->stream.wfd, opts);
applyopts_cloexec(sock->stream.fd2, opts);
/* one-time and input-direction options, no second application */ /* one-time and input-direction options, no second application */
retropt_bool(opts, OPT_IGNOREEOF, &sock->stream.ignoreeof); retropt_bool(opts, OPT_IGNOREEOF, &sock->stream.ignoreeof);
@ -57,7 +56,7 @@ static int xioopen_fifo0(int argc, const char *argv[], struct opt *opts, int xio
} }
/* apply options to first FD */ /* apply options to first FD */
if ((result = applyopts(sock->stream.fd1, opts, PH_ALL)) < 0) { if ((result = applyopts(sock->stream.rfd, opts, PH_ALL)) < 0) {
return result; return result;
} }
if ((result = applyopts_single(&sock->stream, opts, PH_ALL)) < 0) { if ((result = applyopts_single(&sock->stream, opts, PH_ALL)) < 0) {
@ -65,7 +64,7 @@ static int xioopen_fifo0(int argc, const char *argv[], struct opt *opts, int xio
} }
/* apply options to second FD */ /* apply options to second FD */
if ((result = applyopts(sock->stream.fd2, opts2, PH_ALL)) < 0) if ((result = applyopts(sock->stream.wfd, opts2, PH_ALL)) < 0)
{ {
return result; return result;
} }
@ -163,14 +162,14 @@ static int xioopen_fifo1(int argc, const char *argv[], struct opt *opts, int xio
if ((result = _xioopen_open(pipename, rw, opts)) < 0) { if ((result = _xioopen_open(pipename, rw, opts)) < 0) {
return result; return result;
} }
fd->stream.fd1 = result; fd->stream.rfd = result;
fd->stream.fdtype = FDTYPE_SINGLE; fd->stream.wfd = result;
fd->stream.howtoshut = XIOSHUTWR_NONE|XIOSHUTRD_CLOSE; fd->stream.howtoshut = XIOSHUTWR_NONE|XIOSHUTRD_CLOSE;
fd->stream.howtoclose = XIOCLOSE_CLOSE; fd->stream.howtoclose = XIOCLOSE_CLOSE;
applyopts_named(pipename, opts, PH_FD); applyopts_named(pipename, opts, PH_FD);
applyopts(fd->stream.fd1, opts, PH_FD); applyopts(fd->stream.rfd, opts, PH_FD);
applyopts_cloexec(fd->stream.fd1, opts); applyopts_cloexec(fd->stream.rfd, opts);
return _xio_openlate(&fd->stream, opts); return _xio_openlate(&fd->stream, opts);
} }

File diff suppressed because it is too large Load diff

View file

@ -1,34 +1,36 @@
/* source: xio-progcall.h */ /* source: xio-progcall.h */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_progcall_h_included #ifndef __xio_progcall_h_included
#define __xio_progcall_h_included 1 #define __xio_progcall_h_included 1
extern const struct optdesc opt_fdin; extern const struct optdesc opt_leftfd;
extern const struct optdesc opt_fdout; extern const struct optdesc opt_leftinfd;
extern const struct optdesc opt_leftoutfd;
extern const struct optdesc opt_rightfd;
extern const struct optdesc opt_rightinfd;
extern const struct optdesc opt_rightoutfd;
extern const struct optdesc opt_path; extern const struct optdesc opt_path;
extern const struct optdesc opt_pipes; extern const struct optdesc opt_pipes;
extern const struct optdesc opt_pty; extern const struct optdesc opt_pty;
extern const struct optdesc opt_openpty; extern const struct optdesc opt_openpty;
extern const struct optdesc opt_ptmx; extern const struct optdesc opt_ptmx;
extern const struct optdesc opt_commtype;
extern const struct optdesc opt_stderr; extern const struct optdesc opt_stderr;
extern const struct optdesc opt_nofork; extern const struct optdesc opt_nofork;
extern const struct optdesc opt_sighup; extern const struct optdesc opt_sighup;
extern const struct optdesc opt_sigint; extern const struct optdesc opt_sigint;
extern const struct optdesc opt_sigquit; extern const struct optdesc opt_sigquit;
extern int _xioopen_foxec_int(int rw, /* O_RDONLY etc. */ extern int
struct single *fd, _xioopen_progcall(int xioflags, /* XIO_RDONLY etc. */
struct single *xfd,
unsigned groups, unsigned groups,
struct opt **opts, struct opt **opts,
int *duptostderr int *duptostderr,
); bool inter,
extern int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */ int form
struct single *fd,
unsigned groups,
struct opt **opts,
int *duptostderr
); );
extern int setopt_path(struct opt *opts, char **path); extern int setopt_path(struct opt *opts, char **path);

View file

@ -69,11 +69,11 @@ static ssize_t
ssize_t result; ssize_t result;
do { do {
/* we need at least 16 bytes... */ /* we need at least 16 bytes... */
result = Read(xfd->fd1, buff, buflen); result = Read(xfd->rfd, buff, buflen);
} while (result < 0 && errno == EINTR); /*! EAGAIN? */ } while (result < 0 && errno == EINTR); /*! EAGAIN? */
if (result < 0) { if (result < 0) {
Msg4(level, "read(%d, %p, "F_Zu"): %s", Msg4(level, "read(%d, %p, "F_Zu"): %s",
xfd->fd1, buff, buflen, strerror(errno)); xfd->rfd, buff, buflen, strerror(errno));
return result; return result;
} }
if (result == 0) { if (result == 0) {
@ -97,7 +97,7 @@ static int xioopen_proxy_connect2(int argc, const char *argv[], struct opt *opts
bool dofork = false; bool dofork = false;
int result; int result;
if (xfd->fd1 < 0) { if (xfd->rfd < 0) {
Error("xioopen_proxy_connect(): proxyname missing"); Error("xioopen_proxy_connect(): proxyname missing");
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -119,9 +119,8 @@ static int xioopen_proxy_connect2(int argc, const char *argv[], struct opt *opts
proxyvars->targetaddr, proxyvars->targetport); proxyvars->targetaddr, proxyvars->targetport);
xfd->dtype = XIODATA_STREAM; xfd->dtype = XIODATA_STREAM;
xfd->fdtype = FDTYPE_DOUBLE;
applyopts(xfd->fd1, opts, PH_ALL); applyopts(xfd->rfd, opts, PH_ALL);
/*!*/ /*!*/
if ((result = _xio_openlate(xfd, opts)) < 0) if ((result = _xio_openlate(xfd, opts)) < 0)
@ -145,6 +144,7 @@ static int xioopen_proxy_connect3(int argc, const char *argv[], struct opt *opts
int dummy3) { int dummy3) {
/* we expect the form: host:host:port */ /* we expect the form: host:host:port */
struct single *xfd = &xxfd->stream; struct single *xfd = &xxfd->stream;
int rw = (xioflags & XIO_ACCMODE);
struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars; struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars;
const char *proxyname; const char *proxyname;
char *proxyport = NULL; char *proxyport = NULL;
@ -165,7 +165,7 @@ static int xioopen_proxy_connect3(int argc, const char *argv[], struct opt *opts
int level; int level;
int result; int result;
if (xfd->fd1 >= 0) { if (xfd->rfd >= 0) {
Error("xioopen_proxy_connect(): proxyname not allowed here"); Error("xioopen_proxy_connect(): proxyname not allowed here");
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -233,8 +233,10 @@ static int xioopen_proxy_connect3(int argc, const char *argv[], struct opt *opts
default: default:
return result; return result;
} }
xfd->fdtype = FDTYPE_SINGLE; if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
applyopts(xfd->fd1, opts, PH_ALL); if (!XIOWITHRD(rw)) xfd->rfd = -1;
applyopts(xfd->rfd, opts, PH_ALL);
/*!*/ /*!*/
if ((result = _xio_openlate(xfd, opts)) < 0) if ((result = _xio_openlate(xfd, opts)) < 0)
@ -280,8 +282,8 @@ static int xioopen_proxy_connect3(int argc, const char *argv[], struct opt *opts
/* parent process */ /* parent process */
Notice1("forked off child process "F_pid, pid); Notice1("forked off child process "F_pid, pid);
Close(xfd->fd1); Close(xfd->rfd);
Close(xfd->fd2); Close(xfd->wfd);
Nanosleep(&xfd->intervall, NULL); Nanosleep(&xfd->intervall, NULL);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
continue; continue;
@ -345,7 +347,6 @@ int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts,
int _xioopen_proxy_connect(struct single *xfd, int _xioopen_proxy_connect(struct single *xfd,
struct proxyvars *proxyvars, struct proxyvars *proxyvars,
int level) { int level) {
int wfd;
size_t offset; size_t offset;
char request[CONNLEN]; char request[CONNLEN];
char buff[BUFLEN+1]; char buff[BUFLEN+1];
@ -357,8 +358,6 @@ int _xioopen_proxy_connect(struct single *xfd,
int state; int state;
ssize_t sresult; ssize_t sresult;
wfd = (xfd->fdtype == FDTYPE_SINGLE ? xfd->fd1 : xfd->fd2);
/* generate proxy request header - points to final target */ /* generate proxy request header - points to final target */
sprintf(request, "CONNECT %s:%u HTTP/1.0\r\n", sprintf(request, "CONNECT %s:%u HTTP/1.0\r\n",
proxyvars->targetaddr, proxyvars->targetport); proxyvars->targetaddr, proxyvars->targetport);
@ -368,13 +367,13 @@ int _xioopen_proxy_connect(struct single *xfd,
Info1("sending \"%s\"", textbuff); Info1("sending \"%s\"", textbuff);
/* write errors are assumed to always be hard errors, no retry */ /* write errors are assumed to always be hard errors, no retry */
do { do {
sresult = Write(wfd, request, strlen(request)); sresult = Write(xfd->wfd, request, strlen(request));
} while (sresult < 0 && errno == EINTR); } while (sresult < 0 && errno == EINTR);
if (sresult < 0) { if (sresult < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s", Msg4(level, "write(%d, %p, "F_Zu"): %s",
wfd, request, strlen(request), strerror(errno)); xfd->wfd, request, strlen(request), strerror(errno));
if (Close(wfd) < 0) { if (Close(xfd->wfd) < 0) {
Info2("close(%d): %s", xfd->fd2, strerror(errno)); Info2("close(%d): %s", xfd->wfd, strerror(errno));
} }
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -401,13 +400,13 @@ int _xioopen_proxy_connect(struct single *xfd,
Info1("sending \"%s\\r\\n\"", header); Info1("sending \"%s\\r\\n\"", header);
*next++ = '\r'; *next++ = '\n'; *next++ = '\0'; *next++ = '\r'; *next++ = '\n'; *next++ = '\0';
do { do {
sresult = Write(wfd, header, strlen(header)); sresult = Write(xfd->wfd, header, strlen(header));
} while (sresult < 0 && errno == EINTR); } while (sresult < 0 && errno == EINTR);
if (sresult < 0) { if (sresult < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s", Msg4(level, "write(%d, %p, "F_Zu"): %s",
xfd->fd2, header, strlen(header), strerror(errno)); xfd->wfd, header, strlen(header), strerror(errno));
if (Close(wfd/*!*/) < 0) { if (Close(xfd->wfd/*!*/) < 0) {
Info2("close(%d): %s", xfd->fd2, strerror(errno)); Info2("close(%d): %s", xfd->wfd, strerror(errno));
} }
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -417,7 +416,7 @@ int _xioopen_proxy_connect(struct single *xfd,
Info("sending \"\\r\\n\""); Info("sending \"\\r\\n\"");
do { do {
sresult = Write(wfd, "\r\n", 2); sresult = Write(xfd->wfd, "\r\n", 2);
} while (sresult < 0 && errno == EINTR); } while (sresult < 0 && errno == EINTR);
/*! */ /*! */

View file

@ -49,6 +49,7 @@ static int xioopen_pty1(int argc, const char *argv[], struct opt *opts, int xiof
static int xioopen_pty(const char *linkname, struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups) { static int xioopen_pty(const char *linkname, struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups) {
/* we expect the form: filename */ /* we expect the form: filename */
int rw = (xioflags&XIO_ACCMODE);
int ptyfd = -1, ttyfd = -1; int ptyfd = -1, ttyfd = -1;
#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC) #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
bool useptmx = false; /* use /dev/ptmx or equivalent */ bool useptmx = false; /* use /dev/ptmx or equivalent */
@ -179,11 +180,11 @@ static int xioopen_pty(const char *linkname, struct opt *opts, int xioflags, xio
applyopts_cloexec(ptyfd, opts);/*!*/ applyopts_cloexec(ptyfd, opts);/*!*/
xfd->stream.dtype = XIODATA_PTY; xfd->stream.dtype = XIODATA_PTY;
xfd->stream.fdtype = FDTYPE_SINGLE;
applyopts(ptyfd, opts, PH_FD); applyopts(ptyfd, opts, PH_FD);
xfd->stream.fd1 = ptyfd; if (XIOWITHRD(rw)) xfd->stream.rfd = ptyfd;
if (XIOWITHWR(rw)) xfd->stream.wfd = ptyfd;
applyopts(ptyfd, opts, PH_LATE); applyopts(ptyfd, opts, PH_LATE);
if (applyopts_single(&xfd->stream, opts, PH_LATE) < 0) return -1; if (applyopts_single(&xfd->stream, opts, PH_LATE) < 0) return -1;

View file

@ -1,5 +1,5 @@
/* source: xio-rawip.c */ /* source: xio-rawip.c */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of raw IP type */ /* this file contains the source for opening addresses of raw IP type */
@ -104,6 +104,7 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname,
unsigned groups, int *pf) { unsigned groups, int *pf) {
char *garbage; char *garbage;
xiosingle_t *xfd = &xxfd->stream; xiosingle_t *xfd = &xxfd->stream;
int rw = (xioflags&XIO_ACCMODE);
union sockaddr_union us; union sockaddr_union us;
socklen_t uslen; socklen_t uslen;
int feats = 1; /* option bind supports only address, not port */ int feats = 1; /* option bind supports only address, not port */
@ -143,7 +144,6 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname,
uslen = socket_init(*pf, &us); uslen = socket_init(*pf, &us);
xfd->fdtype = FDTYPE_SINGLE;
xfd->dtype = XIODATA_RECVFROM_SKIPIP; xfd->dtype = XIODATA_RECVFROM_SKIPIP;
if (retropt_bind(opts, *pf, socktype, ipproto, &us.soa, &uslen, feats, if (retropt_bind(opts, *pf, socktype, ipproto, &us.soa, &uslen, feats,
@ -151,9 +151,15 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname,
xfd->para.socket.ip.res_opts[1]) != STAT_NOACTION) { xfd->para.socket.ip.res_opts[1]) != STAT_NOACTION) {
needbind = true; needbind = true;
} }
return if ((result =
_xioopen_dgram_sendto(needbind?&us:NULL, uslen, _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, *pf, socktype, ipproto); opts, xioflags, xfd, groups, *pf, socktype,
ipproto)) != STAT_OK) {
return result;
}
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
if (!XIOWITHRD(rw)) xfd->rfd = -1;
return STAT_OK;
} }
@ -251,7 +257,6 @@ int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts,
needbind = true; needbind = true;
} }
xfd->stream.fdtype = FDTYPE_SINGLE;
xfd->stream.dtype = XIODATA_RECVFROM_SKIPIP_ONE; xfd->stream.dtype = XIODATA_RECVFROM_SKIPIP_ONE;
if ((result = if ((result =
_xioopen_dgram_recvfrom(&xfd->stream, xioflags, needbind?&us.soa:NULL, _xioopen_dgram_recvfrom(&xfd->stream, xioflags, needbind?&us.soa:NULL,
@ -314,7 +319,6 @@ int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts,
xfd->stream.para.socket.la.soa.sa_family = pf; xfd->stream.para.socket.la.soa.sa_family = pf;
} }
xfd->stream.fdtype = FDTYPE_SINGLE;
xfd->stream.dtype = XIODATA_RECV_SKIPIP; xfd->stream.dtype = XIODATA_RECV_SKIPIP;
result = result =
_xioopen_dgram_recv(&xfd->stream, xioflags, _xioopen_dgram_recv(&xfd->stream, xioflags,

View file

@ -1,5 +1,5 @@
/* source: xio-readline.c */ /* source: xio-readline.c */
/* Copyright Gerhard Rieger 2002-2008 */ /* Copyright Gerhard Rieger 2002-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening the readline address */ /* this file contains the source for opening the readline address */
@ -63,30 +63,29 @@ static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
xfd->common.flags |= XIO_DOESCONVERT; xfd->common.flags |= XIO_DOESCONVERT;
strcpy(cp, "using "); cp = strchr(cp, '\0'); strcpy(cp, "using "); cp = strchr(cp, '\0');
if ((rw+1)&1) { if (XIOWITHRD(rw)) {
strcpy(cp, "readline on stdin for reading"); cp = strchr(cp, '\0'); strcpy(cp, "readline on stdin for reading"); cp = strchr(cp, '\0');
if ((rw+1)&2) if (XIOWITHWR(rw))
strcpy(cp, " and "); cp = strchr(cp, '\0'); strcpy(cp, " and "); cp = strchr(cp, '\0');
} }
if ((rw+1)&2) { if (XIOWITHWR(rw)) {
strcpy(cp, "stdio for writing"); cp = strchr(cp, '\0'); strcpy(cp, "stdio for writing"); cp = strchr(cp, '\0');
} }
Notice(msgbuf); Notice(msgbuf);
xfd->stream.fd1 = 0; /* stdin */ xfd->stream.rfd = 0; /* stdin */
if ((rw+1) & 2) { if (XIOWITHWR(rw)) {
xfd->stream.fd2 = 1; /* stdout */ xfd->stream.wfd = 1; /* stdout */
} }
xfd->stream.howtoclose = XIOCLOSE_READLINE; xfd->stream.howtoclose = XIOCLOSE_READLINE;
xfd->stream.dtype = XIODATA_READLINE; xfd->stream.dtype = XIODATA_READLINE;
xfd->stream.fdtype = FDTYPE_DOUBLE;
#if WITH_TERMIOS #if WITH_TERMIOS
if (Isatty(xfd->stream.fd1)) { if (Isatty(xfd->stream.rfd)) {
if (Tcgetattr(xfd->stream.fd1, &xfd->stream.savetty) < 0) { if (Tcgetattr(xfd->stream.rfd, &xfd->stream.savetty) < 0) {
Warn2("cannot query current terminal settings on fd %d. %s", Warn2("cannot query current terminal settings on fd %d. %s",
xfd->stream.fd1, strerror(errno)); xfd->stream.rfd, strerror(errno));
} else { } else {
xfd->stream.ttyvalid = true; xfd->stream.ttyvalid = true;
} }
@ -96,7 +95,7 @@ static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1; if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
applyopts2(xfd->stream.fd1, opts, PH_INIT, PH_FD); applyopts2(xfd->stream.rfd, opts, PH_INIT, PH_FD);
Using_history(); Using_history();
applyopts_offset(&xfd->stream, opts); applyopts_offset(&xfd->stream, opts);
@ -130,8 +129,8 @@ static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
Read_history(xfd->stream.para.readline.history_file); Read_history(xfd->stream.para.readline.history_file);
} }
#if _WITH_TERMIOS #if _WITH_TERMIOS
xiotermios_clrflag(xfd->stream.fd1, 3, ICANON); xiotermios_clrflag(xfd->stream.rfd, 3, ICANON);
xiotermios_clrflag(xfd->stream.fd1, 3, ECHO); xiotermios_clrflag(xfd->stream.rfd, 3, ECHO);
#endif /* _WITH_TERMIOS */ #endif /* _WITH_TERMIOS */
return _xio_openlate(&xfd->stream, opts); return _xio_openlate(&xfd->stream, opts);
} }
@ -153,45 +152,45 @@ ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) {
readline */ readline */
struct termios saveterm, setterm; struct termios saveterm, setterm;
*pipe->para.readline.dynend = '\0'; *pipe->para.readline.dynend = '\0';
Tcgetattr(pipe->fd1, &saveterm); /*! error */ Tcgetattr(pipe->rfd, &saveterm); /*! error */
setterm = saveterm; setterm = saveterm;
setterm.c_lflag |= ICANON; setterm.c_lflag |= ICANON;
Tcsetattr(pipe->fd1, TCSANOW, &setterm); /*!*/ Tcsetattr(pipe->rfd, TCSANOW, &setterm); /*!*/
#endif /* _WITH_TERMIOS */ #endif /* _WITH_TERMIOS */
do { do {
bytes = Read(pipe->fd1, buff, bufsiz); bytes = Read(pipe->rfd, buff, bufsiz);
} while (bytes < 0 && errno == EINTR); } while (bytes < 0 && errno == EINTR);
if (bytes < 0) { if (bytes < 0) {
_errno = errno; _errno = errno;
Error4("read(%d, %p, "F_Zu"): %s", Error4("read(%d, %p, "F_Zu"): %s",
pipe->fd1, buff, bufsiz, strerror(_errno)); pipe->rfd, buff, bufsiz, strerror(_errno));
errno = _errno; errno = _errno;
return -1; return -1;
} }
#if _WITH_TERMIOS #if _WITH_TERMIOS
setterm.c_lflag &= ~ICANON; setterm.c_lflag &= ~ICANON;
Tcgetattr(pipe->fd1, &setterm); /*! error */ Tcgetattr(pipe->rfd, &setterm); /*! error */
Tcsetattr(pipe->fd1, TCSANOW, &saveterm); /*!*/ Tcsetattr(pipe->rfd, TCSANOW, &saveterm); /*!*/
#endif /* _WITH_TERMIOS */ #endif /* _WITH_TERMIOS */
pipe->para.readline.dynend = pipe->para.readline.dynprompt; pipe->para.readline.dynend = pipe->para.readline.dynprompt;
/*Write(pipe->fd1, "\n", 1);*/ /*!*/ /*Write(pipe->rfd, "\n", 1);*/ /*!*/
return bytes; return bytes;
} }
#endif /* HAVE_REGEX_H */ #endif /* HAVE_REGEX_H */
#if _WITH_TERMIOS #if _WITH_TERMIOS
xiotermios_setflag(pipe->fd1, 3, ECHO); xiotermios_setflag(pipe->rfd, 3, ECHO);
#endif /* _WITH_TERMIOS */ #endif /* _WITH_TERMIOS */
if (pipe->para.readline.prompt || pipe->para.readline.dynprompt) { if (pipe->para.readline.prompt || pipe->para.readline.dynprompt) {
/* we must carriage return, because readline will first print the /* we must carriage return, because readline will first print the
prompt */ prompt */
ssize_t writt; ssize_t writt;
do { do {
writt = Write(pipe->fd1, "\r", 1); writt = Write(pipe->rfd, "\r", 1);
} while (writt < 0 && errno == EINTR); } while (writt < 0 && errno == EINTR);
if (writt < 0) { if (writt < 0) {
Warn2("write(%d, \"\\r\", 1): %s", Warn2("write(%d, \"\\r\", 1): %s",
pipe->fd1, strerror(errno)); pipe->rfd, strerror(errno));
} else if (writt < 1) { } else if (writt < 1) {
Warn1("write() only wrote "F_Zu" of 1 byte", writt); Warn1("write() only wrote "F_Zu" of 1 byte", writt);
} }
@ -209,7 +208,7 @@ ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) {
return 0; /* EOF */ return 0; /* EOF */
} }
#if _WITH_TERMIOS #if _WITH_TERMIOS
xiotermios_clrflag(pipe->fd1, 3, ECHO); xiotermios_clrflag(pipe->rfd, 3, ECHO);
#endif /* _WITH_TERMIOS */ #endif /* _WITH_TERMIOS */
Add_history(line); Add_history(line);
bytes = strlen(line); bytes = strlen(line);

View file

@ -1,5 +1,5 @@
/* source: xio-socket.c */ /* source: xio-socket.c */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for socket related functions, and the /* this file contains the source for socket related functions, and the
@ -234,6 +234,7 @@ int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd, unsigned groups, int xioflags, xiofile_t *xxfd, unsigned groups,
int dummy1, int dummy2, int dummy3) { int dummy1, int dummy2, int dummy3) {
struct single *xfd = &xxfd->stream; struct single *xfd = &xxfd->stream;
int rw = (xioflags&XIO_ACCMODE);
const char *pfname = argv[1]; const char *pfname = argv[1];
const char *protname = argv[2]; const char *protname = argv[2];
const char *address = argv[3]; const char *address = argv[3];
@ -302,6 +303,8 @@ int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
opts, pf, socktype, proto, false)) != 0) { opts, pf, socktype, proto, false)) != 0) {
return result; return result;
} }
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
if (!XIOWITHRD(rw)) xfd->rfd = -1;
if ((result = _xio_openlate(xfd, opts)) < 0) { if ((result = _xio_openlate(xfd, opts)) < 0) {
return result; return result;
} }
@ -382,6 +385,7 @@ static
int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts, int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd, unsigned groups, int xioflags, xiofile_t *xxfd, unsigned groups,
int dummy1, int dummy2, int dummy3) { int dummy1, int dummy2, int dummy3) {
int rw = (xioflags&XIO_ACCMODE);
int result; int result;
if (argc != 5) { if (argc != 5) {
@ -396,15 +400,22 @@ int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts,
return result; return result;
} }
_xio_openlate(&xxfd->stream, opts); _xio_openlate(&xxfd->stream, opts);
if (XIOWITHWR(rw)) xxfd->stream.wfd = xxfd->stream.rfd;
if (!XIOWITHRD(rw)) xxfd->stream.rfd = -1;
return STAT_OK; return STAT_OK;
} }
/*
returns the resulting FD in xfd->rfd, independend of xioflags
*/
static static
int _xioopen_socket_sendto(const char *pfname, const char *type, int _xioopen_socket_sendto(const char *pfname, const char *type,
const char *protname, const char *address, const char *protname, const char *address,
struct opt *opts, int xioflags, xiofile_t *xxfd, struct opt *opts, int xioflags, xiofile_t *xxfd,
unsigned groups) { unsigned groups) {
xiosingle_t *xfd = &xxfd->stream; xiosingle_t *xfd = &xxfd->stream;
int rw = (xioflags&XIO_ACCMODE);
char *garbage; char *garbage;
union sockaddr_union us = {{0}}; union sockaddr_union us = {{0}};
socklen_t uslen = 0; socklen_t uslen = 0;
@ -484,9 +495,15 @@ int _xioopen_socket_sendto(const char *pfname, const char *type,
needbind = true; needbind = true;
} }
return if ((result =
_xioopen_dgram_sendto(needbind?&us:NULL, uslen, _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf, socktype, proto); opts, xioflags, xfd, groups, pf, socktype, proto))
!= STAT_OK) {
return result;
}
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
if (!XIOWITHRD(rw)) xfd->rfd = -1;
return STAT_OK;
} }
@ -723,6 +740,7 @@ int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
/* a subroutine that is common to all socket addresses that want to connect /* a subroutine that is common to all socket addresses that want to connect
to a peer address. to a peer address.
might fork. might fork.
returns the resulting FD in xfd->rfd
applies and consumes the following options: applies and consumes the following options:
PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
PH_CONNECTED, PH_LATE, PH_CONNECTED, PH_LATE,
@ -741,19 +759,18 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
int _errno; int _errno;
int result; int result;
if ((xfd->fd1 = xiosocket(opts, pf, socktype, protocol, level)) < 0) { if ((xfd->rfd = xiosocket(opts, pf, socktype, protocol, level)) < 0) {
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
xfd->fdtype = FDTYPE_SINGLE;
applyopts_offset(xfd, opts); applyopts_offset(xfd, opts);
applyopts(xfd->fd1, opts, PH_PASTSOCKET); applyopts(xfd->rfd, opts, PH_PASTSOCKET);
applyopts(xfd->fd1, opts, PH_FD); applyopts(xfd->rfd, opts, PH_FD);
applyopts_cloexec(xfd->fd1, opts); applyopts_cloexec(xfd->rfd, opts);
applyopts(xfd->fd1, opts, PH_PREBIND); applyopts(xfd->rfd, opts, PH_PREBIND);
applyopts(xfd->fd1, opts, PH_BIND); applyopts(xfd->rfd, opts, PH_BIND);
#if WITH_TCP || WITH_UDP #if WITH_TCP || WITH_UDP
if (alt) { if (alt) {
union sockaddr_union sin, *sinp; union sockaddr_union sin, *sinp;
@ -810,13 +827,13 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
problem = false; problem = false;
do { /* loop over lowport bind() attempts */ do { /* loop over lowport bind() attempts */
*port = htons(i); *port = htons(i);
if (Bind(xfd->fd1, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) { if (Bind(xfd->rfd, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) {
Msg4(errno==EADDRINUSE?E_INFO:level, Msg4(errno==EADDRINUSE?E_INFO:level,
"bind(%d, {%s}, "F_Zd"): %s", xfd->fd1, "bind(%d, {%s}, "F_Zd"): %s", xfd->rfd,
sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)), sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
sizeof(*sinp), strerror(errno)); sizeof(*sinp), strerror(errno));
if (errno != EADDRINUSE) { if (errno != EADDRINUSE) {
Close(xfd->fd1); Close(xfd->rfd);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} else { } else {
@ -826,7 +843,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
if (i == N) { if (i == N) {
Msg(level, "no low port available"); Msg(level, "no low port available");
/*errno = EADDRINUSE; still assigned */ /*errno = EADDRINUSE; still assigned */
Close(xfd->fd1); Close(xfd->rfd);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} while (i != N); } while (i != N);
@ -834,31 +851,31 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
#endif /* WITH_TCP || WITH_UDP */ #endif /* WITH_TCP || WITH_UDP */
if (us) { if (us) {
if (Bind(xfd->fd1, us, uslen) < 0) { if (Bind(xfd->rfd, us, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
xfd->fd1, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), xfd->rfd, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)),
uslen, strerror(errno)); uslen, strerror(errno));
Close(xfd->fd1); Close(xfd->rfd);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} }
applyopts(xfd->fd1, opts, PH_PASTBIND); applyopts(xfd->rfd, opts, PH_PASTBIND);
applyopts(xfd->fd1, opts, PH_CONNECT); applyopts(xfd->rfd, opts, PH_CONNECT);
if (xfd->para.socket.connect_timeout.tv_sec != 0 || if (xfd->para.socket.connect_timeout.tv_sec != 0 ||
xfd->para.socket.connect_timeout.tv_usec != 0) { xfd->para.socket.connect_timeout.tv_usec != 0) {
fcntl_flags = Fcntl(xfd->fd1, F_GETFL); fcntl_flags = Fcntl(xfd->rfd, F_GETFL);
Fcntl_l(xfd->fd1, F_SETFL, fcntl_flags|O_NONBLOCK); Fcntl_l(xfd->rfd, F_SETFL, fcntl_flags|O_NONBLOCK);
} }
result = Connect(xfd->fd1, (struct sockaddr *)them, themlen); result = Connect(xfd->rfd, (struct sockaddr *)them, themlen);
_errno = errno; _errno = errno;
la.soa.sa_family = them->sa_family; lalen = sizeof(la); la.soa.sa_family = them->sa_family; lalen = sizeof(la);
if (Getsockname(xfd->fd1, &la.soa, &lalen) < 0) { if (Getsockname(xfd->rfd, &la.soa, &lalen) < 0) {
Msg4(level-1, "getsockname(%d, %p, {%d}): %s", Msg4(level-1, "getsockname(%d, %p, {%d}): %s",
xfd->fd1, &la.soa, lalen, strerror(errno)); xfd->rfd, &la.soa, lalen, strerror(errno));
} }
errno = _errno; errno = _errno;
if (result < 0) { if (result < 0) {
@ -870,15 +887,15 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
int result; int result;
Info4("connect(%d, %s, "F_Zd"): %s", Info4("connect(%d, %s, "F_Zd"): %s",
xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), xfd->rfd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
timeout = xfd->para.socket.connect_timeout; timeout = xfd->para.socket.connect_timeout;
writefd.fd = xfd->fd1; writefd.fd = xfd->rfd;
writefd.events = (POLLIN|POLLHUP|POLLERR); writefd.events = (POLLIN|POLLHUP|POLLERR);
result = xiopoll(&writefd, 1, &timeout); result = xiopoll(&writefd, 1, &timeout);
if (result < 0) { if (result < 0) {
Msg4(level, "xiopoll({%d,POLLIN|POLLHUP|POLLER},,{"F_tv_sec"."F_tv_usec"): %s", Msg4(level, "xiopoll({%d,POLLIN|POLLHUP|POLLER},,{"F_tv_sec"."F_tv_usec"): %s",
xfd->fd1, timeout.tv_sec, timeout.tv_usec, strerror(errno)); xfd->rfd, timeout.tv_sec, timeout.tv_usec, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
if (result == 0) { if (result == 0) {
@ -890,23 +907,23 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
if (writefd.revents & POLLOUT) { if (writefd.revents & POLLOUT) {
#if 0 #if 0
unsigned char dummy[1]; unsigned char dummy[1];
Read(xfd->fd1, &dummy, 1); /* get error message */ Read(xfd->rfd, &dummy, 1); /* get error message */
Msg2(level, "connecting to %s: %s", Msg2(level, "connecting to %s: %s",
sockaddr_info(them, infobuff, sizeof(infobuff)), sockaddr_info(them, infobuff, sizeof(infobuff)),
strerror(errno)); strerror(errno));
#else #else
Connect(xfd->fd1, them, themlen); /* get error message */ Connect(xfd->rfd, them, themlen); /* get error message */
Msg4(level, "connect(%d, %s, "F_Zd"): %s", Msg4(level, "connect(%d, %s, "F_Zd"): %s",
xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), xfd->rfd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
#endif #endif
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
/* otherwise OK */ /* otherwise OK */
Fcntl_l(xfd->fd1, F_SETFL, fcntl_flags); Fcntl_l(xfd->rfd, F_SETFL, fcntl_flags);
} else { } else {
Warn4("connect(%d, %s, "F_Zd"): %s", Warn4("connect(%d, %s, "F_Zd"): %s",
xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), xfd->rfd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
} }
} else if (pf == PF_UNIX && errno == EPROTOTYPE) { } else if (pf == PF_UNIX && errno == EPROTOTYPE) {
@ -914,7 +931,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
the only way to distinguish stream and datagram sockets */ the only way to distinguish stream and datagram sockets */
int _errno = errno; int _errno = errno;
Info4("connect(%d, %s, "F_Zd"): %s", Info4("connect(%d, %s, "F_Zd"): %s",
xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), xfd->rfd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
#if 0 #if 0
Info("assuming datagram socket"); Info("assuming datagram socket");
@ -923,21 +940,21 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
memcpy(&xfd->peersa.soa, them, xfd->salen); memcpy(&xfd->peersa.soa, them, xfd->salen);
#endif #endif
/*!!! and remove bind socket */ /*!!! and remove bind socket */
Close(xfd->fd1); xfd->fd1 = -1; Close(xfd->rfd); xfd->rfd = -1;
errno = _errno; errno = _errno;
return -1; return -1;
} else { } else {
Msg4(level, "connect(%d, %s, "F_Zd"): %s", Msg4(level, "connect(%d, %s, "F_Zd"): %s",
xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), xfd->rfd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
Close(xfd->fd1); Close(xfd->rfd);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} }
applyopts_fchown(xfd->fd1, opts); /* OPT_USER, OPT_GROUP */ applyopts_fchown(xfd->rfd, opts); /* OPT_USER, OPT_GROUP */
applyopts(xfd->fd1, opts, PH_CONNECTED); applyopts(xfd->rfd, opts, PH_CONNECTED);
applyopts(xfd->fd1, opts, PH_LATE); applyopts(xfd->rfd, opts, PH_LATE);
Notice1("successfully connected from local address %s", Notice1("successfully connected from local address %s",
sockaddr_info(&la.soa, themlen, infobuff, sizeof(infobuff))); sockaddr_info(&la.soa, themlen, infobuff, sizeof(infobuff)));
@ -954,6 +971,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
PH_CONNECTED, PH_LATE, PH_CONNECTED, PH_LATE,
OFUNC_OFFSET, OFUNC_OFFSET,
OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
returns the resulting FD in xfd->rfd, independend of xioflags
returns 0 on success. returns 0 on success.
*/ */
int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
@ -1030,7 +1048,7 @@ int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
/* parent process */ /* parent process */
Notice1("forked off child process "F_pid, pid); Notice1("forked off child process "F_pid, pid);
Close(xfd->fd1); Close(xfd->rfd);
/* with and without retry */ /* with and without retry */
Nanosleep(&xfd->intervall, NULL); Nanosleep(&xfd->intervall, NULL);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
@ -1055,6 +1073,7 @@ int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
OFUNC_OFFSET OFUNC_OFFSET
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
returns the resulting FD in xfd->rfd, independend of xioflags
*/ */
int _xioopen_dgram_sendto(/* them is already in xfd->peersa */ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
union sockaddr_union *us, socklen_t uslen, union sockaddr_union *us, socklen_t uslen,
@ -1065,42 +1084,42 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
union sockaddr_union la; socklen_t lalen = sizeof(la); union sockaddr_union la; socklen_t lalen = sizeof(la);
char infobuff[256]; char infobuff[256];
if ((xfd->fd1 = xiosocket(opts, pf, socktype, ipproto, level)) < 0) { if ((xfd->rfd = xiosocket(opts, pf, socktype, ipproto, level)) < 0) {
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
applyopts_offset(xfd, opts); applyopts_offset(xfd, opts);
applyopts_single(xfd, opts, PH_PASTSOCKET); applyopts_single(xfd, opts, PH_PASTSOCKET);
applyopts(xfd->fd1, opts, PH_PASTSOCKET); applyopts(xfd->rfd, opts, PH_PASTSOCKET);
applyopts(xfd->fd1, opts, PH_FD); applyopts(xfd->rfd, opts, PH_FD);
applyopts_cloexec(xfd->fd1, opts); applyopts_cloexec(xfd->rfd, opts);
applyopts(xfd->fd1, opts, PH_PREBIND); applyopts(xfd->rfd, opts, PH_PREBIND);
applyopts(xfd->fd1, opts, PH_BIND); applyopts(xfd->rfd, opts, PH_BIND);
if (us) { if (us) {
if (Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) { if (Bind(xfd->rfd, (struct sockaddr *)us, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
xfd->fd1, sockaddr_info((struct sockaddr *)us, uslen, infobuff, sizeof(infobuff)), xfd->rfd, sockaddr_info((struct sockaddr *)us, uslen, infobuff, sizeof(infobuff)),
uslen, strerror(errno)); uslen, strerror(errno));
Close(xfd->fd1); Close(xfd->rfd);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} }
applyopts(xfd->fd1, opts, PH_PASTBIND); applyopts(xfd->rfd, opts, PH_PASTBIND);
/*applyopts(xfd->fd1, opts, PH_CONNECT);*/ /*applyopts(xfd->rfd, opts, PH_CONNECT);*/
if (Getsockname(xfd->fd1, &la.soa, &lalen) < 0) { if (Getsockname(xfd->rfd, &la.soa, &lalen) < 0) {
Warn4("getsockname(%d, %p, {%d}): %s", Warn4("getsockname(%d, %p, {%d}): %s",
xfd->fd1, &la.soa, lalen, strerror(errno)); xfd->rfd, &la.soa, lalen, strerror(errno));
} }
applyopts_fchown(xfd->fd1, opts); applyopts_fchown(xfd->rfd, opts);
applyopts(xfd->fd1, opts, PH_CONNECTED); applyopts(xfd->rfd, opts, PH_CONNECTED);
applyopts(xfd->fd1, opts, PH_LATE); applyopts(xfd->rfd, opts, PH_LATE);
/* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */ /* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */
Notice1("successfully prepared local socket %s", Notice1("successfully prepared local socket %s",
@ -1210,6 +1229,8 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
struct sockaddr *us, socklen_t uslen, struct sockaddr *us, socklen_t uslen,
struct opt *opts, struct opt *opts,
int pf, int socktype, int proto, int level) { int pf, int socktype, int proto, int level) {
int rw = (xioflags&XIO_ACCMODE);
int s;
char *rangename; char *rangename;
socklen_t salen; socklen_t salen;
bool dofork = false; bool dofork = false;
@ -1258,22 +1279,24 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
} }
#endif /* 1 */ #endif /* 1 */
if ((xfd->fd1 = xiosocket(opts, pf, socktype, proto, level)) < 0) { if ((s = xiosocket(opts, pf, socktype, proto, level)) < 0) {
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
if (XIOWITHRD(rw)) xfd->rfd = s;
if (XIOWITHWR(rw)) xfd->wfd = s;
applyopts_single(xfd, opts, PH_PASTSOCKET); applyopts_single(xfd, opts, PH_PASTSOCKET);
applyopts(xfd->fd1, opts, PH_PASTSOCKET); applyopts(xfd->rfd, opts, PH_PASTSOCKET);
applyopts_cloexec(xfd->fd1, opts); applyopts_cloexec(xfd->rfd, opts);
applyopts(xfd->fd1, opts, PH_PREBIND); applyopts(xfd->rfd, opts, PH_PREBIND);
applyopts(xfd->fd1, opts, PH_BIND); applyopts(xfd->rfd, opts, PH_BIND);
if ((us != NULL) && Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) { if ((us != NULL) && Bind(xfd->rfd, (struct sockaddr *)us, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1, Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->rfd,
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
strerror(errno)); strerror(errno));
Close(xfd->fd1); Close(xfd->rfd);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -1283,7 +1306,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
} }
#endif #endif
applyopts(xfd->fd1, opts, PH_PASTBIND); applyopts(xfd->rfd, opts, PH_PASTBIND);
#if WITH_UNIX #if WITH_UNIX
if (pf == AF_UNIX && us != NULL) { if (pf == AF_UNIX && us != NULL) {
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
@ -1368,7 +1391,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
if (drop) { if (drop) {
char *dummy[2]; char *dummy[2];
Recv(xfd->fd1, dummy, sizeof(dummy), 0); Recv(xfd->rfd, dummy, sizeof(dummy), 0);
drop = true; drop = true;
} }
@ -1381,7 +1404,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
} else { } else {
Notice1("receiving IP protocol %u", proto); Notice1("receiving IP protocol %u", proto);
} }
readfd.fd = xfd->fd1; readfd.fd = xfd->rfd;
readfd.events = POLLIN; readfd.events = POLLIN;
if (xiopoll(&readfd, 1, NULL) > 0) { if (xiopoll(&readfd, 1, NULL) > 0) {
break; break;
@ -1391,8 +1414,8 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
continue; continue;
} }
Msg2(level, "xiopoll({%d,,},,-1): %s", xfd->fd1, strerror(errno)); Msg2(level, "xiopoll({%d,,},,-1): %s", xfd->rfd, strerror(errno));
Close(xfd->fd1); Close(xfd->rfd);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} while (true); } while (true);
@ -1404,7 +1427,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
msgh.msg_controllen = sizeof(ctrlbuff); msgh.msg_controllen = sizeof(ctrlbuff);
#endif #endif
if (xiogetpacketsrc(xfd->fd1, &msgh) < 0) { if (xiogetpacketsrc(xfd->rfd, &msgh) < 0) {
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
palen = msgh.msg_namelen; palen = msgh.msg_namelen;
@ -1418,7 +1441,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
if (xiocheckpeer(xfd, pa, la) < 0) { if (xiocheckpeer(xfd, pa, la) < 0) {
/* drop packet */ /* drop packet */
char buff[512]; char buff[512];
Recv(xfd->fd1, buff, sizeof(buff), 0); Recv(xfd->rfd, buff, sizeof(buff), 0);
continue; continue;
} }
Info1("permitting packet from %s", Info1("permitting packet from %s",
@ -1429,9 +1452,9 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
/*xiosetsockaddrenv("SOCK", la, lalen, proto);*/ /*xiosetsockaddrenv("SOCK", la, lalen, proto);*/
xiosetsockaddrenv("PEER", pa, palen, proto); xiosetsockaddrenv("PEER", pa, palen, proto);
applyopts(xfd->fd1, opts, PH_FD); applyopts(xfd->rfd, opts, PH_FD);
applyopts(xfd->fd1, opts, PH_CONNECTED); applyopts(xfd->rfd, opts, PH_CONNECTED);
xfd->peersa = *(union sockaddr_union *)pa; xfd->peersa = *(union sockaddr_union *)pa;
xfd->salen = palen; xfd->salen = palen;
@ -1450,7 +1473,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
Sigprocmask(SIG_BLOCK, &mask_sigchldusr1, NULL); Sigprocmask(SIG_BLOCK, &mask_sigchldusr1, NULL);
if ((pid = xio_fork(false, level)) < 0) { if ((pid = xio_fork(false, level)) < 0) {
Close(xfd->fd1); Close(xfd->rfd);
Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL); Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -1505,27 +1528,31 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
struct sockaddr *us, socklen_t uslen, struct sockaddr *us, socklen_t uslen,
struct opt *opts, int pf, int socktype, int proto, struct opt *opts, int pf, int socktype, int proto,
int level) { int level) {
int rw = (xioflags&XIO_ACCMODE);
int s;
char *rangename; char *rangename;
char infobuff[256]; char infobuff[256];
if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY; if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
if ((xfd->fd1 = xiosocket(opts, pf, socktype, proto, level)) < 0) { if ((s = xiosocket(opts, pf, socktype, proto, level)) < 0) {
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
if (XIOWITHRD(rw)) xfd->rfd = s;
if (XIOWITHWR(rw)) xfd->wfd = s;
applyopts_single(xfd, opts, PH_PASTSOCKET); applyopts_single(xfd, opts, PH_PASTSOCKET);
applyopts(xfd->fd1, opts, PH_PASTSOCKET); applyopts(xfd->rfd, opts, PH_PASTSOCKET);
applyopts_cloexec(xfd->fd1, opts); applyopts_cloexec(xfd->rfd, opts);
applyopts(xfd->fd1, opts, PH_PREBIND); applyopts(xfd->rfd, opts, PH_PREBIND);
applyopts(xfd->fd1, opts, PH_BIND); applyopts(xfd->rfd, opts, PH_BIND);
if ((us != NULL) && Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) { if ((us != NULL) && Bind(xfd->rfd, (struct sockaddr *)us, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1, Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->rfd,
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
strerror(errno)); strerror(errno));
Close(xfd->fd1); Close(xfd->rfd);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -1535,7 +1562,7 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
} }
#endif #endif
applyopts(xfd->fd1, opts, PH_PASTBIND); applyopts(xfd->rfd, opts, PH_PASTBIND);
#if WITH_UNIX #if WITH_UNIX
if (pf == AF_UNIX && us != NULL) { if (pf == AF_UNIX && us != NULL) {
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
@ -2165,11 +2192,6 @@ xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]) {
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_int(opts, OPT_SO_PROTOTYPE, &proto); retropt_int(opts, OPT_SO_PROTOTYPE, &proto);
result = Socketpair(pf, socktype, proto, sv); result = xiosocketpair2(pf, socktype, proto, sv);
if (result < 0) {
Error5("socketpair(%d, %d, %d, %p): %s",
pf, socktype, proto, sv, strerror(errno));
return -1;
}
return result; return result;
} }

View file

@ -1,5 +1,5 @@
/* source: xio-socks.c */ /* source: xio-socks.c */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of socks4 type */ /* this file contains the source for opening addresses of socks4 type */
@ -60,6 +60,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
int dummy3) { int dummy3) {
/* we expect the form: host:host:port */ /* we expect the form: host:host:port */
struct single *xfd = &xxfd->stream; struct single *xfd = &xxfd->stream;
int rw = (xioflags&XIO_ACCMODE);
struct opt *opts0 = NULL; struct opt *opts0 = NULL;
const char *sockdname; char *sockdport; const char *sockdname; char *sockdport;
const char *targetname, *targetport; const char *targetname, *targetport;
@ -86,7 +87,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
} }
if (argc == 3) { if (argc == 3) {
if (xfd->fd1 < 0) { if (xfd->rfd < 0) {
Error("xioopen_socks4_connect(): socksservername missing"); Error("xioopen_socks4_connect(): socksservername missing");
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -94,7 +95,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
targetname = argv[1]; targetname = argv[1];
targetport = argv[2]; targetport = argv[2];
} else /* if (argc == 4) */ { } else /* if (argc == 4) */ {
if (xfd->fd1 >= 0) { if (xfd->rfd >= 0) {
Error("xioopen_socks4_connect(): socksservername not allowed here"); Error("xioopen_socks4_connect(): socksservername not allowed here");
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -112,7 +113,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
result = _xioopen_socks4_prepare(targetport, opts, &sockdport, sockhead, &buflen); result = _xioopen_socks4_prepare(targetport, opts, &sockdport, sockhead, &buflen);
if (result != STAT_OK) return result; if (result != STAT_OK) return result;
if (xfd->fd2 < 0) { if (xfd->wfd < 0) {
result = result =
_xioopen_ipapp_prepare(opts, &opts0, sockdname, sockdport, _xioopen_ipapp_prepare(opts, &opts0, sockdname, sockdport,
&pf, ipproto, &pf, ipproto,
@ -159,7 +160,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
return result; return result;
} }
if (xfd->fd2 < 0) { if (xfd->wfd < 0) {
/* this cannot fork because we retrieved fork option above */ /* this cannot fork because we retrieved fork option above */
result = result =
_xioopen_connect (xfd, _xioopen_connect (xfd,
@ -179,14 +180,14 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
default: default:
return result; return result;
} }
xfd->fdtype = FDTYPE_SINGLE; if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
if (!XIOWITHRD(rw)) xfd->rfd = -1;
} else { } else {
xfd->dtype = XIODATA_STREAM; xfd->dtype = XIODATA_STREAM;
xfd->fdtype = FDTYPE_DOUBLE;
} }
/*!*/ /*!*/
applyopts(xfd->fd1, opts, PH_ALL); applyopts(xfd->rfd, opts, PH_ALL);
if ((result = _xio_openlate(xfd, opts)) < 0) if ((result = _xio_openlate(xfd, opts)) < 0)
return result; return result;
@ -233,8 +234,8 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
/* parent process */ /* parent process */
Notice1("forked off child process "F_pid, pid); Notice1("forked off child process "F_pid, pid);
Close(xfd->fd1); Close(xfd->rfd);
Close(xfd->fd2); Close(xfd->wfd);
Nanosleep(&xfd->intervall, NULL); Nanosleep(&xfd->intervall, NULL);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
continue; continue;
@ -348,7 +349,7 @@ int _xioopen_socks4_connect(struct single *xfd,
struct socks4head *replyhead = (struct socks4head *)buff; struct socks4head *replyhead = (struct socks4head *)buff;
char *destdomname = NULL; char *destdomname = NULL;
wfd = (xfd->fdtype == FDTYPE_SINGLE ? xfd->fd1 : xfd->fd2); wfd =xfd->wfd;
/* send socks header (target addr+port, +auth) */ /* send socks header (target addr+port, +auth) */
#if WITH_MSGLEVEL <= E_INFO #if WITH_MSGLEVEL <= E_INFO
@ -384,8 +385,8 @@ int _xioopen_socks4_connect(struct single *xfd,
if (Close(wfd) < 0) { if (Close(wfd) < 0) {
Info2("close(%d): %s", wfd, strerror(errno)); Info2("close(%d): %s", wfd, strerror(errno));
} }
if (Close(xfd->fd1) < 0) { if (Close(xfd->rfd) < 0) {
Info2("close(%d): %s", xfd->fd1, strerror(errno)); Info2("close(%d): %s", xfd->rfd, strerror(errno));
} }
return STAT_RETRYLATER; /* retry complete open cycle */ return STAT_RETRYLATER; /* retry complete open cycle */
} }
@ -395,14 +396,14 @@ int _xioopen_socks4_connect(struct single *xfd,
while (bytes >= 0) { /* loop over answer chunks until complete or error */ while (bytes >= 0) { /* loop over answer chunks until complete or error */
/* receive socks answer */ /* receive socks answer */
do { do {
result = Read(xfd->fd1, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes); result = Read(xfd->rfd, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes);
} while (result < 0 && errno == EINTR); } while (result < 0 && errno == EINTR);
if (result < 0) { if (result < 0) {
Msg4(level, "read(%d, %p, "F_Zu"): %s", Msg4(level, "read(%d, %p, "F_Zu"): %s",
xfd->fd1, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes, xfd->rfd, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes,
strerror(errno)); strerror(errno));
if (Close(xfd->fd1) < 0) { if (Close(xfd->rfd) < 0) {
Info2("close(%d): %s", xfd->fd1, strerror(errno)); Info2("close(%d): %s", xfd->rfd, strerror(errno));
} }
if (Close(wfd) < 0) { if (Close(wfd) < 0) {
Info2("close(%d): %s", wfd, strerror(errno)); Info2("close(%d): %s", wfd, strerror(errno));
@ -410,8 +411,8 @@ int _xioopen_socks4_connect(struct single *xfd,
} }
if (result == 0) { if (result == 0) {
Msg(level, "read(): EOF during read of socks reply, peer might not be a socks4 server"); Msg(level, "read(): EOF during read of socks reply, peer might not be a socks4 server");
if (Close(xfd->fd1) < 0) { if (Close(xfd->rfd) < 0) {
Info2("close(%d): %s", xfd->fd1, strerror(errno)); Info2("close(%d): %s", xfd->rfd, strerror(errno));
} }
if (Close(wfd) < 0) { if (Close(wfd) < 0) {
Info2("close(%d): %s", wfd, strerror(errno)); Info2("close(%d): %s", wfd, strerror(errno));

View file

@ -1,5 +1,5 @@
/* source: xio-socks5.c */ /* source: xio-socks5.c */
/* Copyright Gerhard Rieger 2004-2007 */ /* Copyright Gerhard Rieger 2004-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of socks5 type */ /* this file contains the source for opening addresses of socks5 type */
@ -42,27 +42,27 @@ static int xiosocks5_recvbytes(struct single *xfd,
/* receive socks answer */ /* receive socks answer */
Debug("waiting for data from peer"); Debug("waiting for data from peer");
do { do {
result = Read(xfd->fd1, buff+bytes, buflen-bytes); result = Read(xfd->rfd, buff+bytes, buflen-bytes);
} while (result < 0 && errno == EINTR); } while (result < 0 && errno == EINTR);
if (result < 0) { if (result < 0) {
Msg4(level, "read(%d, %p, "F_Zu"): %s", Msg4(level, "read(%d, %p, "F_Zu"): %s",
xfd->fd1, buff+bytes, buflen-bytes, xfd->rfd, buff+bytes, buflen-bytes,
strerror(errno)); strerror(errno));
if (Close(xfd->fd1) < 0) { if (Close(xfd->rfd) < 0) {
Warn2("close(%d): %s", xfd->fd1, strerror(errno)); Warn2("close(%d): %s", xfd->rfd, strerror(errno));
} }
if (Close(xfd->fd2) < 0) { if (Close(xfd->wfd) < 0) {
Warn2("close(%d): %s", xfd->fd2, strerror(errno)); Warn2("close(%d): %s", xfd->wfd, strerror(errno));
} }
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
if (result == 0) { if (result == 0) {
Msg(level, "read(): EOF during read of socks reply"); Msg(level, "read(): EOF during read of socks reply");
if (Close(xfd->fd1) < 0) { if (Close(xfd->rfd) < 0) {
Warn2("close(%d): %s", xfd->fd1, strerror(errno)); Warn2("close(%d): %s", xfd->rfd, strerror(errno));
} }
if (Close(xfd->fd2) < 0) { if (Close(xfd->wfd) < 0) {
Warn2("close(%d): %s", xfd->fd2, strerror(errno)); Warn2("close(%d): %s", xfd->wfd, strerror(errno));
} }
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -107,7 +107,7 @@ static int xioopen_socks5_client(int argc, const char *argv[],
if (result != STAT_OK) return result; if (result != STAT_OK) return result;
#endif #endif
if (xfd->fd1 < 0) { if (xfd->rfd < 0) {
Error("socks5 must be used as embedded address"); Error("socks5 must be used as embedded address");
return -1; return -1;
} }
@ -166,7 +166,7 @@ static int xioopen_socks5_client(int argc, const char *argv[],
default: default:
return result; return result;
} }
xfd->fd1 = xfd->fd2 = xfd->fd; xfd->fd1 = xfd->wfd = xfd->fd;
} else } else
#endif #endif
xfd->dtype = XIODATA_STREAM; xfd->dtype = XIODATA_STREAM;
@ -188,7 +188,7 @@ static int xioopen_socks5_client(int argc, const char *argv[],
} }
/*!*/ /*!*/
applyopts(xfd->fd1, opts, PH_ALL); applyopts(xfd->rfd, opts, PH_ALL);
if ((result = _xio_openlate(xfd, opts)) < 0) if ((result = _xio_openlate(xfd, opts)) < 0)
return result; return result;
@ -236,16 +236,16 @@ int _xioopen_socks5_connect(struct single *xfd,
/* send socks header (target addr+port, +auth) */ /* send socks header (target addr+port, +auth) */
Info("sending socks5 identifier/method selection message"); Info("sending socks5 identifier/method selection message");
do { do {
result = Write(xfd->fd2, sendmethod, sendlen); result = Write(xfd->wfd, sendmethod, sendlen);
} while (result < 0 && errno == EINTR); } while (result < 0 && errno == EINTR);
if (result < 0) { if (result < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s", Msg4(level, "write(%d, %p, "F_Zu"): %s",
xfd->fd2, sendmethod, sendlen, strerror(errno)); xfd->wfd, sendmethod, sendlen, strerror(errno));
if (Close(xfd->fd2) < 0) { if (Close(xfd->wfd) < 0) {
Warn2("close(%d): %s", xfd->fd2, strerror(errno)); Warn2("close(%d): %s", xfd->wfd, strerror(errno));
} }
if (Close(xfd->fd1) < 0) { if (Close(xfd->rfd) < 0) {
Warn2("close(%d): %s", xfd->fd1, strerror(errno)); Warn2("close(%d): %s", xfd->rfd, strerror(errno));
} }
return STAT_RETRYLATER; /* retry complete open cycle */ return STAT_RETRYLATER; /* retry complete open cycle */
} }
@ -308,16 +308,16 @@ int _xioopen_socks5_connect(struct single *xfd,
/* send socks request (target addr+port, +auth) */ /* send socks request (target addr+port, +auth) */
Info("sending socks5 request selection"); Info("sending socks5 request selection");
do { do {
result = Write(xfd->fd2, sendrequest, sendlen); result = Write(xfd->wfd, sendrequest, sendlen);
} while (result < 0 && errno == EINTR); } while (result < 0 && errno == EINTR);
if (result < 0) { if (result < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s", Msg4(level, "write(%d, %p, "F_Zu"): %s",
xfd->fd2, sendmethod, sendlen, strerror(errno)); xfd->wfd, sendmethod, sendlen, strerror(errno));
if (Close(xfd->fd2) < 0) { if (Close(xfd->wfd) < 0) {
Warn2("close(%d): %s", xfd->fd2, strerror(errno)); Warn2("close(%d): %s", xfd->wfd, strerror(errno));
} }
if (Close(xfd->fd1) < 0) { if (Close(xfd->rfd) < 0) {
Warn2("close(%d): %s", xfd->fd1, strerror(errno)); Warn2("close(%d): %s", xfd->rfd, strerror(errno));
} }
return STAT_RETRYLATER; /* retry complete open cycle */ return STAT_RETRYLATER; /* retry complete open cycle */
} }
@ -467,16 +467,16 @@ int xio_socks5_dialog(int level, struct single *xfd,
/* send socks header (target addr+port, +auth) */ /* send socks header (target addr+port, +auth) */
Info1("sending socks5 %s message", descr); Info1("sending socks5 %s message", descr);
do { do {
result = Write(xfd->fd2, sendbuff, sendlen); result = Write(xfd->wfd, sendbuff, sendlen);
} while (result < 0 && errno == EINTR); } while (result < 0 && errno == EINTR);
if (result < 0) { if (result < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s", Msg4(level, "write(%d, %p, "F_Zu"): %s",
xfd->fd2, sendbuff, sendlen, strerror(errno)); xfd->wfd, sendbuff, sendlen, strerror(errno));
if (Close(xfd->fd2) < 0) { if (Close(xfd->wfd) < 0) {
Warn2("close(%d): %s", xfd->fd2, strerror(errno)); Warn2("close(%d): %s", xfd->wfd, strerror(errno));
} }
if (Close(xfd->fd1) < 0) { if (Close(xfd->rfd) < 0) {
Warn2("close(%d): %s", xfd->fd1, strerror(errno)); Warn2("close(%d): %s", xfd->rfd, strerror(errno));
} }
return STAT_RETRYLATER; /* retry complete open cycle */ return STAT_RETRYLATER; /* retry complete open cycle */
} }

View file

@ -1,5 +1,5 @@
/* source: xio-stdio.c */ /* source: xio-stdio.c */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses stdio type */ /* this file contains the source for opening addresses stdio type */
@ -20,10 +20,10 @@ static int xioopen_stdfd(int argc, const char *argv[], struct opt *opts, int xio
/* we specify all option groups that we can imagine for a FD, becasue the /* we specify all option groups that we can imagine for a FD, becasue the
changed parsing mechanism does not allow us to check the type of FD before changed parsing mechanism does not allow us to check the type of FD before
applying the options */ applying the options */
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_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_UNSPEC, 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_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_UNSPEC, 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_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_UNSPEC, 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) }; 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_UNSPEC, XIOCLOSE_NONE, xioopen_stdfd, 2, 0, 0 HELP(NULL) };
const union xioaddr_desc *xioaddrs_stdio[] = { const union xioaddr_desc *xioaddrs_stdio[] = {
(union xioaddr_desc *)&xioaddr_stdio0, NULL }; (union xioaddr_desc *)&xioaddr_stdio0, NULL };
@ -40,28 +40,26 @@ int xioopen_stdio_bi(xiofile_t *sock) {
unsigned int groups1 = xioaddr_stdio0.groups, groups2 = xioaddr_stdio0.groups; unsigned int groups1 = xioaddr_stdio0.groups, groups2 = xioaddr_stdio0.groups;
int result; int result;
sock->stream.fd1 = 0 /*stdin*/; sock->stream.rfd = 0 /*stdin*/;
sock->stream.fd2 = 1 /*stdout*/; sock->stream.wfd = 1 /*stdout*/;
sock->stream.fdtype = FDTYPE_DOUBLE;
#if WITH_TERMIOS #if WITH_TERMIOS
if (Isatty(sock->stream.fd1)) { if (Isatty(sock->stream.rfd)) {
if (Tcgetattr(sock->stream.fd1, if (Tcgetattr(sock->stream.rfd,
&sock->stream.savetty) &sock->stream.savetty)
< 0) { < 0) {
Warn2("cannot query current terminal settings on fd %d: %s", Warn2("cannot query current terminal settings on fd %d: %s",
sock->stream.fd1, strerror(errno)); sock->stream.rfd, strerror(errno));
} else { } else {
sock->stream.ttyvalid = true; sock->stream.ttyvalid = true;
} }
} }
if (Isatty(sock->stream.fd2)) { if (Isatty(sock->stream.wfd) && (sock->stream.wfd != sock->stream.rfd)) {
if (Tcgetattr(sock->stream.fd2, if (Tcgetattr(sock->stream.wfd,
&sock->stream.savetty) &sock->stream.savetty)
< 0) { < 0) {
Warn2("cannot query current terminal settings on fd %d: %s", Warn2("cannot query current terminal settings on fd %d: %s",
sock->stream.wfd, strerror(errno));
sock->stream.fd2, strerror(errno));
} else { } else {
sock->stream.ttyvalid = true; sock->stream.ttyvalid = true;
} }
@ -70,6 +68,8 @@ int xioopen_stdio_bi(xiofile_t *sock) {
if (applyopts_single(&sock->stream, sock->stream.opts, PH_INIT) < 0) if (applyopts_single(&sock->stream, sock->stream.opts, PH_INIT) < 0)
return -1; return -1;
applyopts(-1, sock->stream.opts, PH_INIT); applyopts(-1, sock->stream.opts, PH_INIT);
if (sock->stream.howtoshut == XIOSHUT_UNSPEC)
sock->stream.howtoshut = XIOSHUT_NONE;
/* options here are one-time and one-direction, no second use */ /* options here are one-time and one-direction, no second use */
retropt_bool(sock->stream.opts, OPT_IGNOREEOF, &sock->stream.ignoreeof); retropt_bool(sock->stream.opts, OPT_IGNOREEOF, &sock->stream.ignoreeof);
@ -89,7 +89,7 @@ int xioopen_stdio_bi(xiofile_t *sock) {
} }
/* apply options to first FD */ /* apply options to first FD */
if ((result = applyopts(sock->stream.fd1, opts1, PH_ALL)) < 0) { if ((result = applyopts(sock->stream.rfd, opts1, PH_ALL)) < 0) {
return result; return result;
} }
if ((result = _xio_openlate(&sock->stream, opts1)) < 0) { if ((result = _xio_openlate(&sock->stream, opts1)) < 0) {
@ -100,7 +100,7 @@ int xioopen_stdio_bi(xiofile_t *sock) {
return -1; return -1;
} }
/* apply options to second FD */ /* apply options to second FD */
if ((result = applyopts(sock->stream.fd2, opts2, PH_ALL)) < 0) { if ((result = applyopts(sock->stream.wfd, opts2, PH_ALL)) < 0) {
return result; return result;
} }
if ((result = _xio_openlate(&sock->stream, opts2)) < 0) { if ((result = _xio_openlate(&sock->stream, opts2)) < 0) {
@ -118,7 +118,7 @@ int xioopen_stdio_bi(xiofile_t *sock) {
/* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw. /* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw.
Do not set FD_CLOEXEC flag. */ Do not set FD_CLOEXEC flag. */
static int xioopen_stdio(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) { static int xioopen_stdio(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) {
int rw = (xioflags&XIO_ACCMODE); int rw = (xioflags&XIO_ACCMODE);
if (argc != 1) { if (argc != 1) {
@ -126,13 +126,16 @@ static int xioopen_stdio(int argc, const char *argv[], struct opt *opts, int xio
} }
if (rw == XIO_RDWR) { if (rw == XIO_RDWR) {
return xioopen_stdio_bi(fd); return xioopen_stdio_bi(xfd);
} }
Notice2("using %s for %s", Notice2("using %s for %s",
&("stdin\0\0\0stdout"[rw<<3]), &("stdin\0\0\0stdout"[rw<<3]),
ddirection[rw]); ddirection[rw]);
return xioopen_fd(opts, rw, fd, rw, -1, dummy2, dummy3); return xioopen_fd(opts, rw, xfd,
XIOWITHRD(rw)?0:-1,
XIOWITHWR(rw)?1:-1,
dummy2, dummy3);
} }
/* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw. /* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw.
@ -146,6 +149,9 @@ static int xioopen_stdfd(int argc, const char *argv[], struct opt *opts, int xio
Notice2("using %s for %s", Notice2("using %s for %s",
&("stdin\0\0\0stdout\0\0stderr"[fd<<3]), &("stdin\0\0\0stdout\0\0stderr"[fd<<3]),
ddirection[rw]); ddirection[rw]);
return xioopen_fd(opts, rw, xfd, fd, -1, dummy2, dummy3); return xioopen_fd(opts, rw, xfd,
XIOWITHRD(rw)?fd:-1,
XIOWITHWR(rw)?fd:-1,
dummy2, dummy3);
} }
#endif /* WITH_STDIO */ #endif /* WITH_STDIO */

View file

@ -1,5 +1,5 @@
/* source: xio-system.c */ /* source: xio-system.c */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of system type */ /* this file contains the source for opening addresses of system type */
@ -17,21 +17,41 @@ static int xioopen_system(int arg, const char *argv[], struct opt *opts,
int xioflags, /* XIO_RDONLY etc. */ int xioflags, /* XIO_RDONLY etc. */
xiofile_t *fd, xiofile_t *fd,
unsigned groups, unsigned groups,
int dummy1, int dummy2, int dummy3 int inter, int form, int dummy3
); );
static const struct xioaddr_endpoint_desc xioendpoint_system1 = { XIOADDR_SYS, "system", 1, XIOBIT_ALL, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_system, 1, 0, 0 HELP(":<shell-command>") }; /* the endpoint variant: get stdin and/or stdout on "left" side. socat does not
provide a "right" side for script */
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, false, 0, 0 HELP(":<shell-command>") };
/* the inter address variant: the bidirectional form has stdin and stdout on
its "left" side, and FDs 3 (for reading) and FD 4 (for writing) on its right
side. */
static const struct xioaddr_inter_desc xiointer_system1_2rw = { XIOADDR_INTER, "system", 1, XIOBIT_RDWR, 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, true, 2, 0, XIOBIT_RDWR HELP(":<shell-command>") };
static const struct xioaddr_inter_desc xiointer_system1_2ro = { XIOADDR_INTER, "system", 1, XIOBIT_RDONLY, 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, true, 2, 0, XIOBIT_WRONLY HELP(":<shell-command>") };
static const struct xioaddr_inter_desc xiointer_system1_2wo = { XIOADDR_INTER, "system", 1, XIOBIT_WRONLY, 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, true, 2, 0, XIOBIT_RDONLY HELP(":<shell-command>") };
/* the unidirectional inter address variant: the "left" side reads from stdin,
and the right side reads from stdout. */
static const struct xioaddr_inter_desc xiointer_system1_1wo = { XIOADDR_INTER, "system1", 1, XIOBIT_WRONLY, 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, true, 1, 0, XIOBIT_RDONLY HELP(":<shell-command>") };
/* the general forms, designed for bidirectional transfer (stdio -- 3,4) */
const union xioaddr_desc *xioaddrs_system[] = { const union xioaddr_desc *xioaddrs_system[] = {
(union xioaddr_desc *)&xioendpoint_system1, (union xioaddr_desc *)&xioendpoint_system1,
(union xioaddr_desc *)&xiointer_system1_2rw,
(union xioaddr_desc *)&xiointer_system1_2ro,
(union xioaddr_desc *)&xiointer_system1_2wo,
NULL NULL
}; };
/* unidirectional inter address (stdin -- stdout) */
const union xioaddr_desc *xioaddrs_system1[] = {
(union xioaddr_desc *)&xiointer_system1_1wo,
NULL };
static int xioopen_system(int argc, const char *argv[], struct opt *opts, static int xioopen_system(int argc, const char *argv[], struct opt *opts,
int xioflags, /* XIO_RDONLY etc. */ int xioflags, /* XIO_RDONLY etc. */
xiofile_t *fd, xiofile_t *fd,
unsigned groups, unsigned groups,
int dummy1, int dummy2, int dummy3 int inter, int form, int dummy3
) { ) {
int status; int status;
char *path = NULL; char *path = NULL;
@ -39,7 +59,7 @@ static int xioopen_system(int argc, const char *argv[], struct opt *opts,
int result; int result;
const char *string = argv[1]; const char *string = argv[1];
status = _xioopen_foxec_end(xioflags, &fd->stream, groups, &opts, &duptostderr); status = _xioopen_progcall(xioflags, &fd->stream, groups, &opts, &duptostderr, inter, form);
if (status < 0) return status; if (status < 0) return status;
if (status == 0) { /* child */ if (status == 0) { /* child */
int numleft; int numleft;

View file

@ -1,10 +1,11 @@
/* source: xio-system.h */ /* source: xio-system.h */
/* Copyright Gerhard Rieger 2001-2007 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_system_h_included #ifndef __xio_system_h_included
#define __xio_system_h_included 1 #define __xio_system_h_included 1
extern const union xioaddr_desc *xioaddrs_system[]; extern const union xioaddr_desc *xioaddrs_system[];
extern const union xioaddr_desc *xioaddrs_system1[];
#endif /* !defined(__xio_system_h_included) */ #endif /* !defined(__xio_system_h_included) */

View file

@ -1,5 +1,5 @@
/* source: xio-tcpwrap.c */ /* source: xio-tcpwrap.c */
/* Copyright Gerhard Rieger 2006-2008 */ /* Copyright Gerhard Rieger 2006-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for tcpwrapper handling stuff */ /* this file contains the source for tcpwrapper handling stuff */
@ -132,11 +132,11 @@ int xio_tcpwrap_check(xiosingle_t *xfd, union sockaddr_union *us,
Warn1("inet_ntop(): %s", strerror(errno)); Warn1("inet_ntop(): %s", strerror(errno));
} }
Debug7("request_init(%p, RQ_FILE, %d, RQ_CLIENT_SIN, {%s:%u}, RQ_SERVER_SIN, {%s:%u}, RQ_DAEMON, \"%s\", 0", Debug7("request_init(%p, RQ_FILE, %d, RQ_CLIENT_SIN, {%s:%u}, RQ_SERVER_SIN, {%s:%u}, RQ_DAEMON, \"%s\", 0",
&ri, xfd->fd1, clientaddr, &ri, xfd->rfd, clientaddr,
ntohs(((struct sockaddr_in *)them)->sin_port), ntohs(((struct sockaddr_in *)them)->sin_port),
serveraddr, ntohs(us->ip4.sin_port), serveraddr, ntohs(us->ip4.sin_port),
xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p')); xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p'));
request_init(&ri, RQ_FILE, xfd->fd1, request_init(&ri, RQ_FILE, xfd->rfd,
RQ_CLIENT_SIN, them, RQ_CLIENT_SIN, them,
RQ_SERVER_SIN, &us->soa, RQ_SERVER_SIN, &us->soa,
RQ_DAEMON, xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p'), 0); RQ_DAEMON, xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p'), 0);

View file

@ -1,5 +1,5 @@
/* source: xio-test.c */ /* source: xio-test.c */
/* Copyright Gerhard Rieger 2007 */ /* Copyright Gerhard Rieger 2007-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for an intermediate test address that appends /* this file contains the source for an intermediate test address that appends
@ -27,9 +27,9 @@ static int xioopen_testrev(int argc, const char *argv[], struct opt *opts,
unsigned groups, int dummy1, int dummy2, unsigned groups, int dummy1, int dummy2,
int dummy3); 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_test0ro = { XIOADDR_PROT, "test", 0, XIOBIT_RDONLY, 0/*groups*/, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, 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_test0wo = { XIOADDR_PROT, "test", 0, XIOBIT_WRONLY, 0/*groups*/, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, 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("") }; static const struct xioaddr_inter_desc xiointer_test0rw = { XIOADDR_PROT, "test", 0, XIOBIT_RDWR, 0/*groups*/, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_test, 0, 0, 0, XIOBIT_RDWR HELP("") };
const union xioaddr_desc *xioaddrs_test[] = { const union xioaddr_desc *xioaddrs_test[] = {
(union xioaddr_desc *)&xiointer_test0ro, (union xioaddr_desc *)&xiointer_test0ro,
@ -59,14 +59,14 @@ static int xioopen_test(int argc, const char *argv[], struct opt *opts,
int result; int result;
assert(argc == 1); assert(argc == 1);
assert(!(xfd->fd1 < 0 && xfd->fd2 < 0)); assert(!(xfd->rfd < 0 && xfd->wfd < 0)); /*!!!*/
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
Notice("opening TEST"); Notice("opening TEST");
xfd->dtype = XIODATA_TEST; xfd->dtype = XIODATA_TEST;
applyopts(xfd->fd1, opts, PH_ALL); applyopts(xfd->rfd, opts, PH_ALL);
if ((result = _xio_openlate(xfd, opts)) < 0) if ((result = _xio_openlate(xfd, opts)) < 0)
return result; return result;
return 0; return 0;
@ -80,14 +80,14 @@ static int xioopen_testuni(int argc, const char *argv[], struct opt *opts,
int result; int result;
assert(argc == 1); assert(argc == 1);
assert(!(xfd->fd1 < 0 && xfd->fd2 < 0)); assert(!(xfd->rfd < 0 && xfd->wfd < 0)); /*!!!*/
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
Notice("opening TESTUNI"); Notice("opening TESTUNI");
xfd->dtype = XIODATA_TESTUNI; xfd->dtype = XIODATA_TESTUNI;
applyopts(xfd->fd1, opts, PH_ALL); applyopts(xfd->rfd, opts, PH_ALL);
if ((result = _xio_openlate(xfd, opts)) < 0) if ((result = _xio_openlate(xfd, opts)) < 0)
return result; return result;
return 0; return 0;
@ -101,21 +101,21 @@ static int xioopen_testrev(int argc, const char *argv[], struct opt *opts,
int result; int result;
assert(argc == 1); assert(argc == 1);
assert(!(xfd->fd1 < 0 && xfd->fd2 < 0)); assert(!(xfd->rfd < 0 && xfd->wfd < 0)); /*!!!*/
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
Notice("opening TESTREV"); Notice("opening TESTREV");
xfd->dtype = XIODATA_TESTREV; xfd->dtype = XIODATA_TESTREV;
applyopts(xfd->fd1, opts, PH_ALL); applyopts(xfd->rfd, opts, PH_ALL);
if ((result = _xio_openlate(xfd, opts)) < 0) if ((result = _xio_openlate(xfd, opts)) < 0)
return result; return result;
return 0; return 0;
} }
size_t xioread_test(struct single *sfd, void *buff, size_t bufsiz) { size_t xioread_test(struct single *sfd, void *buff, size_t bufsiz) {
int fd = sfd->fd1; int fd = sfd->rfd;
ssize_t bytes; ssize_t bytes;
int _errno; int _errno;
@ -143,7 +143,7 @@ size_t xioread_test(struct single *sfd, void *buff, size_t bufsiz) {
} }
size_t xiowrite_test(struct single *sfd, const void *buff, size_t bytes) { size_t xiowrite_test(struct single *sfd, const void *buff, size_t bytes) {
int fd = ((sfd->fdtype==FDTYPE_DOUBLE)?sfd->fd2:sfd->fd1); int fd = sfd->wfd;
void *buff1; void *buff1;
ssize_t writt; ssize_t writt;
int _errno; int _errno;
@ -184,7 +184,7 @@ size_t xiowrite_test(struct single *sfd, const void *buff, size_t bytes) {
} }
size_t xiowrite_testrev(struct single *sfd, const void *buff, size_t bytes) { size_t xiowrite_testrev(struct single *sfd, const void *buff, size_t bytes) {
int fd = ((sfd->fdtype==FDTYPE_DOUBLE)?sfd->fd2:sfd->fd1); int fd = sfd->wfd;
void *buff1; void *buff1;
ssize_t writt; ssize_t writt;
int _errno; int _errno;

View file

@ -1,5 +1,5 @@
/* source: xio-tun.c */ /* source: xio-tun.c */
/* Copyright Gerhard Rieger 2007-2008 */ /* Copyright Gerhard Rieger 2007-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of tun/tap type */ /* this file contains the source for opening addresses of tun/tap type */
@ -105,7 +105,8 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
Notice("creating tunnel network interface"); Notice("creating tunnel network interface");
if ((result = _xioopen_open(tundevice, rw, opts)) < 0) if ((result = _xioopen_open(tundevice, rw, opts)) < 0)
return result; return result;
xfd->stream.fd1 = result; if (XIOWITHRD(rw)) xfd->stream.rfd = result;
if (XIOWITHWR(rw)) xfd->stream.wfd = result;
/* prepare configuration of the new network interface */ /* prepare configuration of the new network interface */
memset(&ifr, 0,sizeof(ifr)); memset(&ifr, 0,sizeof(ifr));
@ -136,10 +137,10 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
} }
} }
if (Ioctl(xfd->stream.fd1, TUNSETIFF, &ifr) < 0) { if (Ioctl(xfd->stream.rfd, TUNSETIFF, &ifr) < 0) {
Error3("ioctl(%d, TUNSETIFF, {\"%s\"}: %s", Error3("ioctl(%d, TUNSETIFF, {\"%s\"}: %s",
xfd->stream.fd1, ifr.ifr_name, strerror(errno)); xfd->stream.rfd, ifr.ifr_name, strerror(errno));
Close(xfd->stream.fd1); Close(xfd->stream.rfd);
} }
/*===================== setting interface properties =====================*/ /*===================== setting interface properties =====================*/
@ -147,7 +148,7 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
/* we seem to need a socket for manipulating the interface */ /* we seem to need a socket for manipulating the interface */
if ((sockfd = Socket(PF_INET, SOCK_DGRAM, 0)) < 0) { if ((sockfd = Socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
Error1("socket(PF_INET, SOCK_DGRAM, 0): %s", strerror(errno)); Error1("socket(PF_INET, SOCK_DGRAM, 0): %s", strerror(errno));
sockfd = xfd->stream.fd1; /* desparate fallback attempt */ sockfd = xfd->stream.rfd; /* desparate fallback attempt */
} }
/*--------------------- setting interface address and netmask ------------*/ /*--------------------- setting interface address and netmask ------------*/
@ -201,10 +202,10 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
#if LATER #if LATER
applyopts_named(tundevice, opts, PH_FD); applyopts_named(tundevice, opts, PH_FD);
#endif #endif
applyopts(xfd->stream.fd1, opts, PH_FD); applyopts(xfd->stream.rfd, opts, PH_FD);
applyopts_cloexec(xfd->stream.fd1, opts); applyopts_cloexec(xfd->stream.rfd, opts);
applyopts_fchown(xfd->stream.fd1, opts); applyopts_fchown(xfd->stream.rfd, opts);
if ((result = _xio_openlate(&xfd->stream, opts)) < 0) if ((result = _xio_openlate(&xfd->stream, opts)) < 0)
return result; return result;

View file

@ -1,5 +1,5 @@
/* source: xio-udp.c */ /* source: xio-udp.c */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for handling UDP addresses */ /* this file contains the source for handling UDP addresses */
@ -96,6 +96,7 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *fd, int xioflags, xiofile_t *fd,
unsigned groups, int pf, int ipproto, unsigned groups, int pf, int ipproto,
int protname) { int protname) {
int rw = (xioflags&XIO_ACCMODE);
const char *portname = argv[1]; const char *portname = argv[1];
union sockaddr_union us; union sockaddr_union us;
union sockaddr_union themunion; union sockaddr_union themunion;
@ -130,8 +131,6 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1; if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
fd->stream.fdtype = FDTYPE_SINGLE;
uslen = socket_init(pf, &us); uslen = socket_init(pf, &us);
retropt_bind(opts, pf, socktype, IPPROTO_UDP, retropt_bind(opts, pf, socktype, IPPROTO_UDP,
(struct sockaddr *)&us, &uslen, 1, (struct sockaddr *)&us, &uslen, 1,
@ -194,36 +193,36 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
union sockaddr_union _sockname; union sockaddr_union _sockname;
union sockaddr_union *la = &_sockname; /* local address */ union sockaddr_union *la = &_sockname; /* local address */
if ((fd->stream.fd1 = xiosocket(opts, pf, socktype, ipproto, E_ERROR)) < 0) { if ((fd->stream.rfd = xiosocket(opts, pf, socktype, ipproto, E_ERROR)) < 0) {
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
/*0 Info4("socket(%d, %d, %d) -> %d", pf, socktype, ipproto, fd->stream.fd);*/ /*0 Info4("socket(%d, %d, %d) -> %d", pf, socktype, ipproto, fd->stream.fd);*/
applyopts(fd->stream.fd1, opts, PH_PASTSOCKET); applyopts(fd->stream.rfd, opts, PH_PASTSOCKET);
if (Setsockopt(fd->stream.fd1, opt_so_reuseaddr.major, if (Setsockopt(fd->stream.rfd, opt_so_reuseaddr.major,
opt_so_reuseaddr.minor, &one, sizeof(one)) < 0) { opt_so_reuseaddr.minor, &one, sizeof(one)) < 0) {
Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd"): %s", Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd"): %s",
fd->stream.fd1, opt_so_reuseaddr.major, fd->stream.rfd, opt_so_reuseaddr.major,
opt_so_reuseaddr.minor, one, sizeof(one), strerror(errno)); opt_so_reuseaddr.minor, one, sizeof(one), strerror(errno));
} }
applyopts_cloexec(fd->stream.fd1, opts); applyopts_cloexec(fd->stream.rfd, opts);
applyopts(fd->stream.fd1, opts, PH_PREBIND); applyopts(fd->stream.rfd, opts, PH_PREBIND);
applyopts(fd->stream.fd1, opts, PH_BIND); applyopts(fd->stream.rfd, opts, PH_BIND);
if (Bind(fd->stream.fd1, &us.soa, uslen) < 0) { if (Bind(fd->stream.rfd, &us.soa, uslen) < 0) {
Error4("bind(%d, {%s}, "F_Zd"): %s", fd->stream.fd1, Error4("bind(%d, {%s}, "F_Zd"): %s", fd->stream.rfd,
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)), sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)),
uslen, strerror(errno)); uslen, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
/* under some circumstances bind() fills sockaddr with interesting info. */ /* under some circumstances bind() fills sockaddr with interesting info. */
if (Getsockname(fd->stream.fd1, &us.soa, &uslen) < 0) { if (Getsockname(fd->stream.rfd, &us.soa, &uslen) < 0) {
Error4("getsockname(%d, %p, {%d}): %s", Error4("getsockname(%d, %p, {%d}): %s",
fd->stream.fd1, &us.soa, uslen, strerror(errno)); fd->stream.rfd, &us.soa, uslen, strerror(errno));
} }
applyopts(fd->stream.fd1, opts, PH_PASTBIND); applyopts(fd->stream.rfd, opts, PH_PASTBIND);
Notice1("listening on UDP %s", Notice1("listening on UDP %s",
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff))); sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)));
readfd.fd = fd->stream.fd1; readfd.fd = fd->stream.rfd;
readfd.events = POLLIN|POLLERR; readfd.events = POLLIN|POLLERR;
while (xiopoll(&readfd, 1, NULL) < 0) { while (xiopoll(&readfd, 1, NULL) < 0) {
if (errno != EINTR) break; if (errno != EINTR) break;
@ -231,12 +230,12 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
themlen = socket_init(pf, them); themlen = socket_init(pf, them);
do { do {
result = Recvfrom(fd->stream.fd1, buff1, 1, MSG_PEEK, result = Recvfrom(fd->stream.rfd, buff1, 1, MSG_PEEK,
&them->soa, &themlen); &them->soa, &themlen);
} while (result < 0 && errno == EINTR); } while (result < 0 && errno == EINTR);
if (result < 0) { if (result < 0) {
Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_Zu"}): %s", Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_Zu"}): %s",
fd->stream.fd1, buff1, fd->stream.rfd, buff1,
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)), sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
@ -247,8 +246,8 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
if (xiocheckpeer(&fd->stream, them, la) < 0) { if (xiocheckpeer(&fd->stream, them, la) < 0) {
/* drop packet */ /* drop packet */
char buff[512]; char buff[512];
Recv(fd->stream.fd1, buff, sizeof(buff), 0); /* drop packet */ Recv(fd->stream.rfd, buff, sizeof(buff), 0); /* drop packet */
Close(fd->stream.fd1); Close(fd->stream.rfd);
continue; continue;
} }
Info1("permitting UDP connection from %s", Info1("permitting UDP connection from %s",
@ -267,8 +266,8 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
/* server: continue loop with socket()+recvfrom() */ /* server: continue loop with socket()+recvfrom() */
/* when we dont close this we get awkward behaviour on Linux 2.4: /* when we dont close this we get awkward behaviour on Linux 2.4:
recvfrom gives 0 bytes with invalid socket address */ recvfrom gives 0 bytes with invalid socket address */
if (Close(fd->stream.fd1) < 0) { if (Close(fd->stream.rfd) < 0) {
Info2("close(%d): %s", fd->stream.fd1, strerror(errno)); Info2("close(%d): %s", fd->stream.rfd, strerror(errno));
} }
Sleep(1); /*! give child a chance to consume the old packet */ Sleep(1); /*! give child a chance to consume the old packet */
@ -277,29 +276,32 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
break; break;
} }
applyopts(fd->stream.fd1, opts, PH_CONNECT); applyopts(fd->stream.rfd, opts, PH_CONNECT);
if ((result = Connect(fd->stream.fd1, &them->soa, themlen)) < 0) { if ((result = Connect(fd->stream.rfd, &them->soa, themlen)) < 0) {
Error4("connect(%d, {%s}, "F_Zd"): %s", Error4("connect(%d, {%s}, "F_Zd"): %s",
fd->stream.fd1, fd->stream.rfd,
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)), sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
/* set the env vars describing the local and remote sockets */ /* set the env vars describing the local and remote sockets */
if (Getsockname(fd->stream.fd1, &us.soa, &uslen) < 0) { if (Getsockname(fd->stream.rfd, &us.soa, &uslen) < 0) {
Warn4("getsockname(%d, %p, {%d}): %s", Warn4("getsockname(%d, %p, {%d}): %s",
fd->stream.fd1, &us.soa, uslen, strerror(errno)); fd->stream.rfd, &us.soa, uslen, strerror(errno));
} }
xiosetsockaddrenv("SOCK", &us, uslen, IPPROTO_UDP); xiosetsockaddrenv("SOCK", &us, uslen, IPPROTO_UDP);
xiosetsockaddrenv("PEER", them, themlen, IPPROTO_UDP); xiosetsockaddrenv("PEER", them, themlen, IPPROTO_UDP);
applyopts_fchown(fd->stream.fd1, opts); applyopts_fchown(fd->stream.rfd, opts);
applyopts(fd->stream.fd1, opts, PH_LATE); applyopts(fd->stream.rfd, opts, PH_LATE);
if ((result = _xio_openlate(&fd->stream, opts)) < 0) if ((result = _xio_openlate(&fd->stream, opts)) < 0)
return result; return result;
if (XIOWITHWR(rw)) fd->stream.wfd = fd->stream.rfd;
if (!XIOWITHRD(rw)) fd->stream.rfd = -1;
return 0; return 0;
} }
@ -338,6 +340,7 @@ int _xioopen_udp_sendto(const char *hostname, const char *servname,
int xioflags, xiofile_t *xxfd, unsigned groups, int xioflags, xiofile_t *xxfd, unsigned groups,
int pf, int socktype, int ipproto) { int pf, int socktype, int ipproto) {
xiosingle_t *xfd = &xxfd->stream; xiosingle_t *xfd = &xxfd->stream;
int rw = (xioflags&XIO_ACCMODE);
union sockaddr_union us; union sockaddr_union us;
socklen_t uslen; socklen_t uslen;
int feats = 3; /* option bind supports address and port */ int feats = 3; /* option bind supports address and port */
@ -405,9 +408,15 @@ int _xioopen_udp_sendto(const char *hostname, const char *servname,
} }
xfd->dtype = XIODATA_RECVFROM; xfd->dtype = XIODATA_RECVFROM;
return _xioopen_dgram_sendto(needbind?&us:NULL, uslen, if ((result =
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, opts, xioflags, xfd, groups,
pf, socktype, ipproto); pf, socktype, ipproto)) != STAT_OK) {
return result;
}
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
if (!XIOWITHRD(rw)) xfd->rfd = -1;
return STAT_OK;
} }

View file

@ -1,5 +1,5 @@
/* source: xio-unix.c */ /* source: xio-unix.c */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of UNIX socket type */ /* this file contains the source for opening addresses of UNIX socket type */
@ -205,6 +205,7 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
/* we expect the form: filename */ /* we expect the form: filename */
const char *name; const char *name;
struct single *xfd = &xxfd->stream; struct single *xfd = &xxfd->stream;
int rw = (xioflags&XIO_ACCMODE);
int pf = PF_UNIX; int pf = PF_UNIX;
int socktype = SOCK_STREAM; int socktype = SOCK_STREAM;
int protocol = 0; int protocol = 0;
@ -252,6 +253,8 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
opts, pf, socktype, protocol, false)) != 0) { opts, pf, socktype, protocol, false)) != 0) {
return result; return result;
} }
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
if (!XIOWITHRD(rw)) xfd->rfd = -1;
if ((result = _xio_openlate(xfd, opts)) < 0) { if ((result = _xio_openlate(xfd, opts)) < 0) {
return result; return result;
} }
@ -259,10 +262,14 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
} }
/*
returns the resulting FD in xfd->rfd, independend of xioflags
*/
static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy, int dummy3) { static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy, int dummy3) {
/* we expect the form: filename */ /* we expect the form: filename */
const char *name; const char *name;
xiosingle_t *xfd = &xxfd->stream; xiosingle_t *xfd = &xxfd->stream;
int rw = (xioflags&XIO_ACCMODE);
int pf = PF_UNIX; int pf = PF_UNIX;
int socktype = SOCK_DGRAM; int socktype = SOCK_DGRAM;
int protocol = 0; int protocol = 0;
@ -271,6 +278,7 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i
bool tight = true; bool tight = true;
bool needbind = false; bool needbind = false;
bool opt_unlink_close = false; bool opt_unlink_close = false;
int result;
if (argc != 2) { if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)", Error2("%s: wrong number of parameters (%d instead of 1)",
@ -310,10 +318,15 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
return if ((result =
_xioopen_dgram_sendto(needbind?&us:NULL, uslen, _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, opts, xioflags, xfd, groups,
pf, socktype, protocol); pf, socktype, protocol)) != STAT_OK) {
return result;
}
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
if (!XIOWITHRD(rw)) xfd->rfd = -1;
return STAT_OK;
} }
@ -472,6 +485,7 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i
int int
_xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups, _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
int abstract, struct opt *opts, const char *name) { int abstract, struct opt *opts, const char *name) {
int rw = (xioflags&XIO_ACCMODE);
int pf = PF_UNIX; int pf = PF_UNIX;
int socktype = 0; /* to be determined by server socket type */ int socktype = 0; /* to be determined by server socket type */
int protocol = 0; int protocol = 0;
@ -537,6 +551,8 @@ _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
xfd->dtype = XIODATA_RECVFROM; xfd->dtype = XIODATA_RECVFROM;
} }
} }
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
if (!XIOWITHRD(rw)) xfd->rfd = -1;
if ((result = _xio_openlate(xfd, opts)) < 0) { if ((result = _xio_openlate(xfd, opts)) < 0) {
return result; return result;
} }

59
xio.h
View file

@ -1,5 +1,5 @@
/* source: xio.h */ /* source: xio.h */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_h_included #ifndef __xio_h_included
@ -59,6 +59,9 @@ struct opt;
/* reverse the direction pattern */ /* reverse the direction pattern */
#define XIOBIT_REVERSE(x) (((x)&XIOBIT_RDWR)|(((x)&XIOBIT_RDONLY)?XIOBIT_WRONLY:0)|(((x)&XIOBIT_WRONLY)?XIOBIT_RDONLY:0)) #define XIOBIT_REVERSE(x) (((x)&XIOBIT_RDWR)|(((x)&XIOBIT_RDONLY)?XIOBIT_WRONLY:0)|(((x)&XIOBIT_WRONLY)?XIOBIT_RDONLY:0))
#define XIOWITHRD(rw) ((rw+1)&(XIO_RDONLY+1))
#define XIOWITHWR(rw) ((rw+1)&(XIO_WRONLY+1))
/* methods for reading and writing, and for related checks */ /* methods for reading and writing, and for related checks */
#define XIODATA_READMASK 0xf000 /* mask for basic r/w method */ #define XIODATA_READMASK 0xf000 /* mask for basic r/w method */
#define XIOREAD_STREAM 0x1000 /* read() (default) */ #define XIOREAD_STREAM 0x1000 /* read() (default) */
@ -125,7 +128,8 @@ struct opt;
#define XIOSHUT_CLOSE (XIOSHUTRD_CLOSE|XIOSHUTWR_CLOSE) #define XIOSHUT_CLOSE (XIOSHUTRD_CLOSE|XIOSHUTWR_CLOSE)
#define XIOSHUT_DOWN (XIOSHUTRD_DOWN|XIOSHUTWR_DOWN) #define XIOSHUT_DOWN (XIOSHUTRD_DOWN|XIOSHUTWR_DOWN)
#define XIOSHUT_KILL (XIOSHUTRD_KILL|XIOSHUTWR_KILL) #define XIOSHUT_KILL (XIOSHUTRD_KILL|XIOSHUTWR_KILL)
#define XIOSHUT_OPENSSL 0x0100 /* specific action on openssl */ #define XIOSHUT_PTYEOF 0x0100 /* change pty to icanon and write VEOF */
#define XIOSHUT_OPENSSL 0x0101 /* specific action on openssl */
/*!!!*/ /*!!!*/
#define XIOCLOSE_UNSPEC 0x0000 /* after init, when no end-close... option */ #define XIOCLOSE_UNSPEC 0x0000 /* after init, when no end-close... option */
@ -136,8 +140,8 @@ struct opt;
#define XIOCLOSE_CLOSE_SIGTERM 0x0005 /* close fd, then send SIGTERM */ #define XIOCLOSE_CLOSE_SIGTERM 0x0005 /* close fd, then send SIGTERM */
#define XIOCLOSE_CLOSE_SIGKILL 0x0006 /* close fd, then send SIGKILL */ #define XIOCLOSE_CLOSE_SIGKILL 0x0006 /* close fd, then send SIGKILL */
#define XIOCLOSE_SLEEP_SIGTERM 0x0007 /* short sleep, then SIGTERM */ #define XIOCLOSE_SLEEP_SIGTERM 0x0007 /* short sleep, then SIGTERM */
#define XIOCLOSE_OPENSSL 0x0100 #define XIOCLOSE_OPENSSL 0x0101
#define XIOCLOSE_READLINE 0x0101 #define XIOCLOSE_READLINE 0x0102
/* these are the values allowed for the "enum xiotag tag" flag of the "struct /* these are the values allowed for the "enum xiotag tag" flag of the "struct
single" and "union bipipe" (xiofile_t) structures. */ single" and "union bipipe" (xiofile_t) structures. */
@ -150,6 +154,17 @@ enum xiotag {
streams */ streams */
} ; } ;
/* inter address communication types */
enum xiocomm {
XIOCOMM_SOCKETPAIRS, /* two unix (local) socket pairs */
XIOCOMM_PIPES, /* two unnamed pipes (fifos) */
XIOCOMM_SOCKETPAIR, /* one unix (local) socket pairs */
XIOCOMM_PTYS, /* two pseudo terminals, each from master to slave */
XIOCOMM_PTY, /* one pseudo terminal, master on left side */
XIOCOMM_TCP, /* one TCP socket pair */
XIOCOMM_TCP4, /* one TCP/IPv4 socket pair */
XIOCOMM_TCP4_LISTEN, /* right side listens for TCP/IPv4, left connects */
} ;
union bipipe; union bipipe;
@ -159,6 +174,16 @@ union bipipe;
#define XIOADDR_SYS XIOADDR_ENDPOINT #define XIOADDR_SYS XIOADDR_ENDPOINT
#define XIOADDR_PROT XIOADDR_INTER #define XIOADDR_PROT XIOADDR_INTER
/* one side of an "extended socketpair" */
typedef struct fddesc {
int rfd; /* used for reading */
int wfd; /* used for writing */
bool single; /* rfd and wfd refer to the same "file" */
int dtype; /* specifies methods for reading and writing */
int howtoshut; /* specifies method for shutting down wfd */
int howtoclose; /* specifies method for closing rfd and wfd */
} xiofd_t;
struct xioaddr_inter_desc { struct xioaddr_inter_desc {
int tag; /* 0: endpoint addr; 1: inter addr */ int tag; /* 0: endpoint addr; 1: inter addr */
const char *defname; /* main (canonical) name of address */ const char *defname; /* main (canonical) name of address */
@ -217,7 +242,8 @@ union xioaddr_desc {
} ; } ;
union xioaddr_descp { union xioaddr_descp {
struct xioaddr_common_desc *common_desc; struct xioaddr_common_desc *
common_desc;
int *tag; /* 0: endpoint addr; 1: inter addr */ int *tag; /* 0: endpoint addr; 1: inter addr */
struct xioaddr_inter_desc *inter_desc; struct xioaddr_inter_desc *inter_desc;
struct xioaddr_endpoint_desc *endpoint_desc; struct xioaddr_endpoint_desc *endpoint_desc;
@ -256,6 +282,8 @@ typedef struct {
struct timeval closwait; /* after close of x, die after seconds */ struct timeval closwait; /* after close of x, die after seconds */
bool lefttoright; /* first addr ro, second addr wo */ bool lefttoright; /* first addr ro, second addr wo */
bool righttoleft; /* first addr wo, second addr ro */ bool righttoleft; /* first addr wo, second addr ro */
int pipetype; /* communication (pipe) type; 0: 2 unidirectional
socketpairs; 1: 2 pipes; 2: 1 socketpair */
} xioopts_t; } xioopts_t;
/* pack the description of a lock file */ /* pack the description of a lock file */
@ -305,12 +333,8 @@ typedef struct single {
const char *argv[MAXARGV]; /* address keyword, required args */ const char *argv[MAXARGV]; /* address keyword, required args */
struct opt *opts; /* the options of this address */ struct opt *opts; /* the options of this address */
int lineterm; /* 0..dont touch; 1..CR; 2..CRNL on extern data */ int lineterm; /* 0..dont touch; 1..CR; 2..CRNL on extern data */
int fd1; int rfd; /* was fd1 */
int fd2; int wfd; /* was fd2 */
enum {
FDTYPE_SINGLE, /* only fd1 is in use, for reading and/or writing */
FDTYPE_DOUBLE /* fd2 is in use too - for writing */
} fdtype;
pid_t subaddrpid; /* pid of subaddress (process handling next addr in pid_t subaddrpid; /* pid of subaddress (process handling next addr in
chain) */ chain) */
int subaddrstat; /* state of subaddress process int subaddrstat; /* state of subaddress process
@ -485,8 +509,8 @@ typedef union bipipe {
#define XIO_READABLE(s) (((s)->common.flags+1)&1) #define XIO_READABLE(s) (((s)->common.flags+1)&1)
#define XIO_RDSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]:&(s)->stream) #define XIO_RDSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]:&(s)->stream)
#define XIO_WRSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[1]:&(s)->stream) #define XIO_WRSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[1]:&(s)->stream)
#define XIO_GETRDFD(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]->fd1:(s)->stream.fd1) #define XIO_GETRDFD(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]->rfd:(s)->stream.rfd)
#define _XIO_GETWRFD(s) (((s)->fdtype==FDTYPE_DOUBLE)?(s)->fd2:(s)->fd1) #define _XIO_GETWRFD(s) ((s)->wfd)
#define XIO_GETWRFD(s) (((s)->tag==XIO_TAG_DUAL)?_XIO_GETWRFD((s)->dual.stream[1]):_XIO_GETWRFD(&(s)->stream)) #define XIO_GETWRFD(s) (((s)->tag==XIO_TAG_DUAL)?_XIO_GETWRFD((s)->dual.stream[1]):_XIO_GETWRFD(&(s)->stream))
#define XIO_EOF(s) (XIO_RDSTREAM(s)->eof && !XIO_RDSTREAM(s)->ignoreeof) #define XIO_EOF(s) (XIO_RDSTREAM(s)->eof && !XIO_RDSTREAM(s)->ignoreeof)
@ -562,12 +586,13 @@ struct opt {
/* with threading, the arguments indirectly passed to xioengine() */ /* with threading, the arguments indirectly passed to xioengine() */
struct threadarg_struct { struct threadarg_struct {
int rw; /* one of XIO_RDONLY, ... */
xiofile_t *xfd1; xiofile_t *xfd1;
xiofile_t *xfd2; xiofile_t *xfd2;
} ; } ;
extern const char *PIPESEP; extern const char *PIPESEP;
extern xiofile_t *sock[XIO_MAXSOCK]; extern xiofile_t *sock[XIO_MAXSOCK]; /*!!!*/
/* return values of xioopensingle */ /* return values of xioopensingle */
#define STAT_OK 0 #define STAT_OK 0
@ -589,7 +614,11 @@ extern int xiosetopt(char what, const char *arg);
extern int xioinqopt(char what, char *arg, size_t n); extern int xioinqopt(char what, char *arg, size_t n);
extern xiofile_t *xioopen(const char *args, int xioflags); extern xiofile_t *xioopen(const char *args, int xioflags);
extern xiofile_t *xioopenx(const char *addr, int xioflags, int infd, int outfd); extern xiofile_t *xioopenx(const char *addr, int xioflags, int infd, int outfd);
extern int xiosocketpair2(xiofile_t **xfd1p, xiofile_t **xfd2p, int how, ...); extern int xiosocketpair2(int pf, int socktype, int protocol, int sv[2]);
extern int xiosocketpair3(xiofile_t **xfd1p, xiofile_t **xfd2p, int how, ...);
extern int xiopty(int useptmx, int *ttyfdp, int *ptyfdp);
extern int xiocommpair(int commtype, bool lefttoright, bool righttoleft,
int dual, xiofd_t *left, xiofd_t *right, ...);
extern int xioopensingle(char *addr, xiosingle_t *fd, int xioflags); extern int xioopensingle(char *addr, xiosingle_t *fd, int xioflags);
extern int xioopenhelp(FILE *of, int level); extern int xioopenhelp(FILE *of, int level);

View file

@ -38,8 +38,8 @@ int xioclose1(struct single *pipe) {
sycSSL_free(pipe->para.openssl.ssl); sycSSL_free(pipe->para.openssl.ssl);
pipe->para.openssl.ssl = NULL; pipe->para.openssl.ssl = NULL;
} }
Close(pipe->fd1); pipe->fd1 = -1; Close(pipe->rfd); pipe->rfd = -1;
Close(pipe->fd2); pipe->fd2 = -1; Close(pipe->wfd); pipe->wfd = -1;
if (pipe->para.openssl.ctx) { if (pipe->para.openssl.ctx) {
sycSSL_CTX_free(pipe->para.openssl.ctx); sycSSL_CTX_free(pipe->para.openssl.ctx);
pipe->para.openssl.ctx = NULL; pipe->para.openssl.ctx = NULL;
@ -64,15 +64,20 @@ int xioclose1(struct single *pipe) {
} }
/*PASSTHROUGH*/ /*PASSTHROUGH*/
case XIOCLOSE_CLOSE: case XIOCLOSE_CLOSE:
if (pipe->fd1 >= 0) { if (XIOWITHRD(pipe->flags) && pipe->rfd >= 0) {
if (Close(pipe->fd1) < 0) { if (Close(pipe->rfd) < 0) {
Info2("close(%d): %s", pipe->fd1, strerror(errno)); Info2("close(%d): %s", pipe->rfd, strerror(errno));
}
}
if (XIOWITHWR(pipe->flags) && pipe->wfd >= 0) {
if (Close(pipe->wfd) < 0) {
Info2("close(%d): %s", pipe->wfd, strerror(errno));
} }
} }
break; break;
case XIOCLOSE_SLEEP_SIGTERM: case XIOCLOSE_SLEEP_SIGTERM:
Sleep(1); Usleep(250000);
if (pipe->child.pid > 0) { if (pipe->child.pid > 0) {
if (Kill(pipe->child.pid, SIGTERM) < 0) { if (Kill(pipe->child.pid, SIGTERM) < 0) {
Msg2(errno==ESRCH?E_INFO:E_WARN, "kill(%d, SIGTERM): %s", Msg2(errno==ESRCH?E_INFO:E_WARN, "kill(%d, SIGTERM): %s",
@ -84,6 +89,10 @@ int xioclose1(struct single *pipe) {
case XIOCLOSE_NONE: case XIOCLOSE_NONE:
break; break;
case XIOCLOSE_UNSPEC:
Warn1("xioclose(): no close action specified on 0x%x", pipe);
break;
default: default:
Error2("xioclose(): bad close action 0x%x on 0x%x", pipe->howtoclose, pipe); Error2("xioclose(): bad close action 0x%x on 0x%x", pipe->howtoclose, pipe);
break; break;
@ -91,9 +100,9 @@ int xioclose1(struct single *pipe) {
#if WITH_TERMIOS #if WITH_TERMIOS
if (pipe->ttyvalid) { if (pipe->ttyvalid) {
if (Tcsetattr(pipe->fd1, 0, &pipe->savetty) < 0) { if (Tcsetattr(pipe->rfd, 0, &pipe->savetty) < 0) {
Warn2("cannot restore terminal settings on fd %d: %s", Warn2("cannot restore terminal settings on fd %d: %s",
pipe->fd1, strerror(errno)); pipe->rfd, strerror(errno));
} }
} }
#endif /* WITH_TERMIOS */ #endif /* WITH_TERMIOS */

View file

@ -442,7 +442,7 @@ int _socat(xiofile_t *xfd1, xiofile_t *xfd2) {
if (XIO_RDSTREAM(sock1)->ignoreeof && if (XIO_RDSTREAM(sock1)->ignoreeof &&
!XIO_RDSTREAM(sock1)->actescape && !sock1->stream.closing) { !XIO_RDSTREAM(sock1)->actescape && !sock1->stream.closing) {
Debug1("socket 1 (fd %d) is at EOF, ignoring", Debug1("socket 1 (fd %d) is at EOF, ignoring",
XIO_RDSTREAM(sock1)->fd1); /*! */ XIO_RDSTREAM(sock1)->rfd); /*! */
mayrd1 = true; mayrd1 = true;
polling = 1; /* do not hook this eof fd to poll for pollintv*/ polling = 1; /* do not hook this eof fd to poll for pollintv*/
} else { } else {
@ -465,7 +465,7 @@ int _socat(xiofile_t *xfd1, xiofile_t *xfd2) {
if (XIO_RDSTREAM(sock2)->ignoreeof && if (XIO_RDSTREAM(sock2)->ignoreeof &&
!XIO_RDSTREAM(sock2)->actescape && !sock2->stream.closing) { !XIO_RDSTREAM(sock2)->actescape && !sock2->stream.closing) {
Debug1("socket 2 (fd %d) is at EOF, ignoring", Debug1("socket 2 (fd %d) is at EOF, ignoring",
XIO_RDSTREAM(sock2)->fd1); XIO_RDSTREAM(sock2)->rfd);
mayrd2 = true; mayrd2 = true;
polling = 1; /* do not hook this eof fd to poll for pollintv*/ polling = 1; /* do not hook this eof fd to poll for pollintv*/
} else { } else {

269
xioopen.c
View file

@ -1,5 +1,5 @@
/* source: xioopen.c */ /* source: xioopen.c */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this is the source file of the extended open function */ /* this is the source file of the extended open function */
@ -64,6 +64,8 @@ const struct xioaddrname address_names[] = {
#endif #endif
#if WITH_EXEC #if WITH_EXEC
{ "exec", xioaddrs_exec }, { "exec", xioaddrs_exec },
{ "exec1", xioaddrs_exec1 },
{ "exec2", xioaddrs_exec },
#endif #endif
#if WITH_FDNUM #if WITH_FDNUM
{ "fd", xioaddrs_fdnum }, { "fd", xioaddrs_fdnum },
@ -230,6 +232,8 @@ const struct xioaddrname address_names[] = {
#endif #endif
#if WITH_SYSTEM #if WITH_SYSTEM
{ "system", xioaddrs_system }, { "system", xioaddrs_system },
{ "system1", xioaddrs_system1 },
{ "system2", xioaddrs_system },
#endif #endif
#if (WITH_IP4 || WITH_IP6) && WITH_TCP #if (WITH_IP4 || WITH_IP6) && WITH_TCP
{ "tcp", xioaddrs_tcp_connect }, { "tcp", xioaddrs_tcp_connect },
@ -347,11 +351,9 @@ int xioopen_makedual(xiofile_t *file) {
if ((file->dual.stream[0] = (xiosingle_t *)xioallocfd()) == NULL) if ((file->dual.stream[0] = (xiosingle_t *)xioallocfd()) == NULL)
return -1; return -1;
file->dual.stream[0]->flags = XIO_RDONLY; file->dual.stream[0]->flags = XIO_RDONLY;
file->dual.stream[0]->fdtype = FDTYPE_SINGLE;
if ((file->dual.stream[1] = (xiosingle_t *)xioallocfd()) == NULL) if ((file->dual.stream[1] = (xiosingle_t *)xioallocfd()) == NULL)
return -1; return -1;
file->dual.stream[1]->flags = XIO_WRONLY; file->dual.stream[1]->flags = XIO_WRONLY;
file->dual.stream[1]->fdtype = FDTYPE_SINGLE;
return 0; return 0;
} }
@ -376,9 +378,8 @@ xiofile_t *xioallocfd(void) {
/* fd->common.ignoreeof = false; */ /* fd->common.ignoreeof = false; */
/* fd->common.eof = 0; */ /* fd->common.eof = 0; */
fd->stream.fd1 = -1; fd->stream.rfd = -1;
fd->stream.fd2 = -1; fd->stream.wfd = -1;
fd->stream.fdtype = FDTYPE_SINGLE;
fd->stream.dtype = XIODATA_STREAM; fd->stream.dtype = XIODATA_STREAM;
#if _WITH_SOCKET #if _WITH_SOCKET
/* fd->stream.salen = 0; */ /* fd->stream.salen = 0; */
@ -408,9 +409,11 @@ void xiofreefd(xiofile_t *xfd) {
/* handle one chain of addresses /* handle one chain of addresses
dirs is one of XIO_RDWR, XIO_RDONLY, or XIO_WRONLY rw is one of XIO_RDWR, XIO_RDONLY, or XIO_WRONLY
when finished with this and the following sub addresses we return an xfd
that can be used by the _socat() loop
*/ */
xiofile_t *socat_open(const char *addrs0, int dirs, int flags) { xiofile_t *socat_open(const char *addrs0, int rw, int flags) {
const char *addrs; const char *addrs;
xiosingle_t *sfdA; /* what we just parse(d) */ xiosingle_t *sfdA; /* what we just parse(d) */
xiosingle_t *sfdB; /* what we just parse(d) - second part of dual */ xiosingle_t *sfdB; /* what we just parse(d) - second part of dual */
@ -423,24 +426,23 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
xiofile_t *xfd0; /* what we return */ xiofile_t *xfd0; /* what we return */
xiofile_t *xfd1; /* left hand of engine */ xiofile_t *xfd1; /* left hand of engine */
xiofile_t *xfd2; /* returned by sub address */ xiofile_t *xfd2; /* returned by sub address */
int dirs0, dirs1, dirs2; /* the data directions for respective xfd */ int rw0, rw1, rw2; /* the data directions for respective xfd
int xfd0shut; directions are sepcified as seen by transfer
int xfd0close; engine */
int lefttoright[2]; xiofd_t left, right;
int righttoleft[2];
struct threadarg_struct *thread_arg; struct threadarg_struct *thread_arg;
/*0 pthread_t thread = 0;*/ /*0 pthread_t thread = 0;*/
/*pthread_attr_t attr;*/ /*pthread_attr_t attr;*/
int _errno = 0; int _errno = 0;
Info3("opening address \"%s\", dirs=%d, flags=%d", addrs0, dirs, flags); Info3("opening address \"%s\", rw=%d, flags=0x%x", addrs0, rw, flags);
/* loop over retries */ /* loop over retries, contains nearly the complete function */
while (true) { while (true) {
addrs = addrs0; addrs = addrs0;
skipsp(&addrs); skipsp(&addrs);
dirs0 = dirs; rw0 = rw;
/* here we do not know much: will the next sub address be inter or /* here we do not know much: will the next sub address be inter or
endpoint, single or dual, reverse? */ endpoint, single or dual, reverse? */
@ -462,7 +464,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
/* is it a dual sub address? */ /* is it a dual sub address? */
if (!strncmp(addrs, xioparams->pipesep, strlen(xioparams->pipesep))) { if (!strncmp(addrs, xioparams->pipesep, strlen(xioparams->pipesep))) {
/* yes, found dual-address operator */ /* yes, found dual-address operator */
if (dirs != XIO_RDWR) { if (rw != XIO_RDWR) {
Error("dual address cannot handle single direction data stream"); Error("dual address cannot handle single direction data stream");
} }
skipsp(&addrs); skipsp(&addrs);
@ -506,16 +508,16 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
sfdB.......if not null, we have a dual type address sfdB.......if not null, we have a dual type address
reverseA...sfdA is reverse reverseA...sfdA is reverse
reverseB...if dual address then sfdB is reverse reverseB...if dual address then sfdB is reverse
dirs0......the data directions of xfd0 */ rw0......the data direction of xfd0 */
/* note: with dual inter, sfdB is implicitely reverse */ /* note: with dual inter, sfdB is implicitely reverse */
/* calculate context parameters that are easier to handle */ /* calculate context parameters that are easier to handle */
if (sfdB == NULL) { if (sfdB == NULL) {
srchleftA = mayleftA = (1 << dirs0); srchleftA = mayleftA = (1 << rw0);
srchrightA = mayrightA = (currentisendpoint ? 0 : XIOBIT_ALL); srchrightA = mayrightA = (currentisendpoint ? 0 : XIOBIT_ALL);
if (reverseA) { if (reverseA) {
/*srchrightA = XIOBIT_REVERSE(srchleftA);*/
srchrightA = srchleftA; srchrightA = srchleftA;
/*srchrightA = XIOBIT_REVERSE(srchleftA); no, see what right means*/
srchleftA = XIOBIT_ALL; srchleftA = XIOBIT_ALL;
} }
} else { /* A is only part of dual */ } else { /* A is only part of dual */
@ -533,7 +535,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
} }
} }
if ((true || ((dirs0+1) & (XIO_WRONLY+1))) || currentisendpoint) { if ((true /*0 || ((rw0+1) & (XIO_WRONLY+1))*/) || currentisendpoint) {
if (xioopen_unoverload(sfdA, srchleftA, &isleftA, srchrightA, &isrightA) if (xioopen_unoverload(sfdA, srchleftA, &isleftA, srchrightA, &isrightA)
< 0) { < 0) {
Error1("address \"%s\" can not be used in this context", Error1("address \"%s\" can not be used in this context",
@ -546,7 +548,10 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
sfdA->addrdescs[0]->inter_desc.defname); sfdA->addrdescs[0]->inter_desc.defname);
} }
} }
if (reverseA) { isrightA = isleftA; } if (reverseA) {
int tmp;
tmp = isleftA; isrightA = isleftA; isleftA = tmp;
}
if (sfdB != NULL) { if (sfdB != NULL) {
if (xioopen_unoverload(sfdB, srchleftB, &isleftB, srchrightB, &isrightB) if (xioopen_unoverload(sfdB, srchleftB, &isleftB, srchrightB, &isrightB)
@ -559,11 +564,11 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
/* conflict in directions on right side (xfd1) */ /* conflict in directions on right side (xfd1) */
Error("conflict in data directions");/*!!*/ Error("conflict in data directions");/*!!*/
} }
dirs1 = ((isrightA+1) | (isleftB+1)) - 1; rw1 = ((isrightA+1) | (isleftB+1)) - 1;
} else { } else {
dirs1 = isrightA; rw1 = isrightA;
} }
dirs2 = (dirs1==XIO_RDWR) ? XIO_RDWR : (dirs1==XIO_RDONLY) ? XIO_WRONLY : rw2 = (rw1==XIO_RDWR) ? XIO_RDWR : (rw1==XIO_RDONLY) ? XIO_WRONLY :
XIO_RDONLY; XIO_RDONLY;
/* now we know exactly what to do with the current sub address */ /* now we know exactly what to do with the current sub address */
@ -574,6 +579,8 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
applyopts_offset(sfdB, sfdB->opts); applyopts_offset(sfdB, sfdB->opts);
} }
/* if we found the endpoint address we are almost finished here */
if (currentisendpoint) { if (currentisendpoint) {
if (sfdB != NULL) { if (sfdB != NULL) {
if ((xfd0 = xioallocfd()) == NULL) { if ((xfd0 = xioallocfd()) == NULL) {
@ -587,7 +594,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
xfd0 = (xiofile_t *)sfdA; xfd0 = (xiofile_t *)sfdA;
} }
/* open it and be ready in this thread */ /* open it and be ready in this thread */
if (xioopen_endpoint_dual(xfd0, dirs0|flags) < 0) { if (xioopen_endpoint_dual(xfd0, rw0|flags) < 0) {
xiofreefd(xfd0); xiofreefd(xfd0);
return NULL; return NULL;
} }
@ -599,7 +606,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
/* recursively open the following addresses of chain */ /* recursively open the following addresses of chain */
/* loop over retries if appropriate */ /* loop over retries if appropriate */
do { do {
xfd2 = socat_open(addrs, dirs2, flags); xfd2 = socat_open(addrs, rw2, flags);
if (xfd2 != NULL) { if (xfd2 != NULL) {
break; /* succeeded */ break; /* succeeded */
} }
@ -615,7 +622,8 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
/* only xfd2 is valid here, contains a handle for the rest of the chain /* only xfd2 is valid here, contains a handle for the rest of the chain
*/ */
/* yupp, and the single addresses sfdA and ev.sfdB are valid too */ /* yupp, and the single addresses sfdA and ev.sfdB are valid too, but
not yet opened */
/* what are xfd0, xfd1, and xfd2? /* what are xfd0, xfd1, and xfd2?
consider chain: addr1|addr2 consider chain: addr1|addr2
@ -642,32 +650,41 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
/* prepare FD based communication of current addr with its right neighbor /* prepare FD based communication of current addr with its right neighbor
(xfd0-xfd1) */ (xfd0-xfd1) */
if (1) { {
int sv[2]; switch (xioopts.pipetype) {
if (Socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) { case XIOCOMM_SOCKETPAIR:
Error2("socketpair(PF_UNIX, PF_STREAM, 0, %s): %s", case XIOCOMM_SOCKETPAIRS:
sv, strerror(errno)); if (xiocommpair(xioopts.pipetype,
(rw0+1)&(XIO_WRONLY+1), (rw0+1)&(XIO_RDONLY+1),
sfdB!=0, &left, &right,
PF_UNIX, SOCK_STREAM, 0) != 0) {
return NULL;
}
break;
case XIOCOMM_PTY:
case XIOCOMM_PTYS:
if (xiocommpair(xioopts.pipetype,
(rw0+1)&(XIO_WRONLY+1), (rw0+1)&(XIO_RDONLY+1),
sfdB!=0, &left, &right,
1 /* useptmx */) != 0) {
return NULL;
}
break;
default:
if (xiocommpair(xioopts.pipetype,
(rw0+1)&(XIO_WRONLY+1), (rw0+1)&(XIO_RDONLY+1),
sfdB!=0, &left, &right) != 0) {
return NULL;
}
break;
} }
lefttoright[0] = righttoleft[1] = sv[0];
lefttoright[1] = righttoleft[0] = sv[1];
xfd0shut = XIOSHUT_DOWN;
xfd0close = XIOCLOSE_CLOSE;
/*xfd0fdtype = FDTYPE_SINGLE;*/
} else {
if (Pipe(lefttoright) < 0) {
Error2("pipe(%p): %s", lefttoright, strerror(errno)); }
if (Pipe(righttoleft) < 0) {
Error2("pipe(%p): %s", righttoleft, strerror(errno)); }
xfd0shut = XIOSHUT_CLOSE;
xfd0close = XIOCLOSE_CLOSE;
/*xfd0fdtype = FDTYPE_DOUBLE;*/
} }
/* now assemble xfd0 and xfd1 */ /* now assemble xfd0 and xfd1 */
if (sfdB != NULL && reverseA == reverseB) { if (sfdB != NULL && reverseA == reverseB) {
/* dual address, differing orientation (B is impl.reverse) */ /* dual address, differing orientation (B is impl.reverse) */
/* dual implies (dirs0==dirs1==XIO_RDWR) */ /* dual implies (rw0==rw1==XIO_RDWR) */
if (!reverseA) { if (!reverseA) {
/* A is not reverse, but B */ /* A is not reverse, but B */
char addr[15]; char addr[15];
@ -675,7 +692,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
xfd0 = xioallocfd(); xfd0 = xioallocfd();
xioopen_makedual(xfd0); xioopen_makedual(xfd0);
xfd0->dual.stream[1] = sfdA; xfd0->dual.stream[1] = sfdA;
sprintf(addr, "FD:%u", righttoleft[0]); sprintf(addr, "FD:%u", /*0 righttoleft[0]*/left.rfd);
if ((xfd0->dual.stream[0] = if ((xfd0->dual.stream[0] =
(xiosingle_t *)socat_open(addr, XIO_WRONLY, 0)) (xiosingle_t *)socat_open(addr, XIO_WRONLY, 0))
== NULL) { == NULL) {
@ -686,7 +703,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
xfd1 = xioallocfd(); xfd1 = xioallocfd();
xioopen_makedual(xfd1); xioopen_makedual(xfd1);
xfd1->dual.stream[1] = sfdB; xfd1->dual.stream[1] = sfdB;
sprintf(addr, "FD:%u", lefttoright[0]); sprintf(addr, "FD:%u", /*0 lefttoright[0]*/right.rfd);
if ((xfd1->dual.stream[0] = if ((xfd1->dual.stream[0] =
(xiosingle_t *)socat_open(addr, XIO_RDONLY, 0)) (xiosingle_t *)socat_open(addr, XIO_RDONLY, 0))
== NULL) { == NULL) {
@ -700,7 +717,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
xfd0 = xioallocfd(); xfd0 = xioallocfd();
xioopen_makedual(xfd0); xioopen_makedual(xfd0);
xfd0->dual.stream[0] = sfdB; xfd0->dual.stream[0] = sfdB;
sprintf(addr, "FD:%u", lefttoright[1]); sprintf(addr, "FD:%u", /*0 lefttoright[1]*/left.wfd);
if ((xfd0->dual.stream[1] = if ((xfd0->dual.stream[1] =
(xiosingle_t *)socat_open(addr, XIO_RDONLY, 0)) (xiosingle_t *)socat_open(addr, XIO_RDONLY, 0))
== NULL) { == NULL) {
@ -710,7 +727,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
xfd1 = xioallocfd(); xfd1 = xioallocfd();
xioopen_makedual(xfd1); xioopen_makedual(xfd1);
xfd1->dual.stream[0] = sfdA; xfd1->dual.stream[0] = sfdA;
sprintf(addr, "FD:%u", righttoleft[1]); sprintf(addr, "FD:%u", /*0 righttoleft[1]*/right.wfd);
if ((xfd1->dual.stream[1] = if ((xfd1->dual.stream[1] =
(xiosingle_t *)socat_open(addr, XIO_RDONLY, 0)) (xiosingle_t *)socat_open(addr, XIO_RDONLY, 0))
== NULL) { == NULL) {
@ -718,10 +735,11 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
return NULL; return NULL;
} }
} }
xfd0->dual.stream[0]->fd1 = lefttoright[1]; xfd0->dual.stream[0]->rfd = left.rfd;
xfd0->dual.stream[1]->fd1 = righttoleft[0]; xfd0->dual.stream[1]->wfd = left.wfd;
xfd1->dual.stream[0]->fd1 = righttoleft[1]; xfd1->dual.stream[0]->rfd = right.rfd;
xfd1->dual.stream[1]->fd1 = lefttoright[0]; xfd1->dual.stream[1]->wfd = right.wfd;
} else { } else {
/* either dual with equal directions, or non-dual */ /* either dual with equal directions, or non-dual */
xiofile_t *tfd; /* temp xfd */ xiofile_t *tfd; /* temp xfd */
@ -741,86 +759,123 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
if (!reverseA) { if (!reverseA) {
/* forward */ /* forward */
xfd0 = tfd; xfd0 = tfd;
if (dirs1 == XIO_RDWR) { if (rw1 == XIO_RDWR) {
sprintf(addr, "FD:%u:%u", righttoleft[1], lefttoright[0]); sprintf(addr, "FD:%u:%u", /*0 righttoleft[1]*/right.wfd, /*0 lefttoright[0]*/right.rfd);
} else if (dirs1 == XIO_RDONLY) { } else if (rw1 == XIO_RDONLY) {
sprintf(addr, "FD:%u", lefttoright[0]); sprintf(addr, "FD:%u", /*0 lefttoright[0]*/right.rfd);
} else { } else {
sprintf(addr, "FD:%u", righttoleft[1]); sprintf(addr, "FD:%u", /*0 righttoleft[1]*/right.wfd);
} }
if ((xfd1 = socat_open(addr, dirs1, 0)) == NULL) { if ((xfd1 = socat_open(addr, rw1, 0)) == NULL) {
xiofreefd(xfd0); xiofreefd(xfd2); xiofreefd(xfd0); xiofreefd(xfd2);
return NULL; return NULL;
} }
} else { } else {
/* reverse */ /* reverse */
xfd1 = tfd; xfd1 = tfd;
if (dirs0 == XIO_RDWR) { if (rw0 == XIO_RDWR) {
sprintf(addr, "FD:%u:%u", lefttoright[1], righttoleft[0]); sprintf(addr, "FD:%u:%u", /*0 lefttoright[1]*/left.wfd, /*0 righttoleft[0]*/left.rfd);
} else if (dirs0 == XIO_RDONLY) { } else if (rw0 == XIO_RDONLY) {
sprintf(addr, "FD:%u", righttoleft[0]); sprintf(addr, "FD:%u", /*0 righttoleft[0]*/left.rfd);
} else { } else {
sprintf(addr, "FD:%u", lefttoright[1]); sprintf(addr, "FD:%u", /*0 lefttoright[1]*/left.wfd);
} }
if ((xfd0 = socat_open(addr, XIO_RDWR, 0)) == NULL) { if ((xfd0 = socat_open(addr, rw0/*0 XIO_RDWR*/, 0)) == NULL) {
xiofreefd(xfd1); xiofreefd(xfd2); xiofreefd(xfd1); xiofreefd(xfd2);
return NULL; return NULL;
} }
/* address type FD keeps the FDs open per default, but ... */ /* address type FD keeps the FDs open per default, but ... */
} }
if (xfd0->tag == XIO_TAG_DUAL) { if (xfd0->tag == XIO_TAG_DUAL) {
xfd0->dual.stream[0]->fd1 = lefttoright[1]; xfd0->dual.stream[0]->rfd = /*0 righttoleft[0]*/left.rfd;
xfd0->dual.stream[1]->fd1 = righttoleft[0]; xfd0->dual.stream[1]->wfd = /*0 lefttoright[1]*/left.wfd;
} else { } else {
xfd0->stream.fd1 = righttoleft[0]; xfd0->stream.rfd = /*0 righttoleft[0]*/left.rfd;
xfd0->stream.fd2 = lefttoright[1]; xfd0->stream.wfd = /*0 lefttoright[1]*/left.wfd;
} }
if (xfd1->tag == XIO_TAG_DUAL) { if (xfd1->tag == XIO_TAG_DUAL) {
xfd1->dual.stream[0]->fd1 = righttoleft[1]; xfd1->dual.stream[0]->rfd = /*0 righttoleft[0]*/left.rfd;
xfd1->dual.stream[1]->fd1 = lefttoright[0]; xfd1->dual.stream[1]->rfd = /*0 lefttoright[1]*/left.wfd;
} else { } else {
xfd1->stream.fd1 = lefttoright[0]; xfd1->stream.rfd = /*0 lefttoright[0]*/right.rfd;
xfd1->stream.fd2 = righttoleft[1]; xfd1->stream.wfd = /*0 righttoleft[1]*/right.wfd;
} }
} }
/* address type FD keeps the FDs open per default, but ... */ /* address type FD keeps the FDs open per default, but ... */
if (xfd0->tag == XIO_TAG_DUAL) { if (xfd0->tag == XIO_TAG_DUAL) {
xfd0->dual.stream[0]->howtoshut = xfd0shut; xfd0->dual.stream[0]->howtoshut = left.howtoshut;
xfd0->dual.stream[0]->howtoclose = xfd0close; xfd0->dual.stream[0]->howtoclose = left.howtoclose;
xfd0->dual.stream[1]->howtoshut = xfd0shut; xfd0->dual.stream[0]->dtype = left.dtype;
xfd0->dual.stream[1]->howtoclose = xfd0close; xfd0->dual.stream[1]->howtoshut = right.howtoshut;
xfd0->dual.stream[1]->howtoclose = right.howtoclose;
xfd0->dual.stream[1]->dtype = right.dtype;
} else { } else {
xfd0->stream.howtoshut = xfd0shut; xfd0->stream.howtoshut = left.howtoshut;
xfd0->stream.howtoclose = xfd0close; xfd0->stream.howtoclose = left.howtoclose;
xfd0->stream.dtype = left.dtype;
} }
if (xfd1->tag == XIO_TAG_DUAL) { if (xfd1->tag == XIO_TAG_DUAL) {
xfd1->dual.stream[0]->howtoshut = xfd0shut; xfd1->dual.stream[0]->howtoshut = left.howtoshut;
xfd1->dual.stream[0]->howtoclose = xfd0close; xfd1->dual.stream[0]->howtoclose = left.howtoclose;
xfd1->dual.stream[1]->howtoshut = xfd0shut; xfd1->dual.stream[0]->dtype = left.dtype;
xfd1->dual.stream[1]->howtoclose = xfd0close; xfd1->dual.stream[1]->howtoshut = right.howtoshut;
xfd1->dual.stream[1]->howtoclose = right.howtoclose;
xfd1->dual.stream[1]->dtype = right.dtype;
} else { } else {
xfd1->stream.howtoshut = xfd0shut; xfd1->stream.howtoshut = right.howtoshut;
xfd1->stream.howtoclose = xfd0close; xfd1->stream.howtoclose = right.howtoclose;
xfd1->stream.dtype = right.dtype;
} }
/* here xfd2 is valid and ready for transfer; /* here xfd2 is valid and ready for transfer;
and xfd0 and xfd1 are valid and ready for opening */ and xfd0 and xfd1 are valid and ready for opening */
/* create a new thread that do the xioopen() of xfd1 and xfd2, and then
drive the transfer engine between them */
if ((thread_arg = Malloc(sizeof(struct threadarg_struct))) == NULL) { if ((thread_arg = Malloc(sizeof(struct threadarg_struct))) == NULL) {
/*! free something */ /*! free something */
xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2); xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2);
return NULL; return NULL;
} }
thread_arg->rw = (reverseA ? rw1 : rw0);
thread_arg->xfd1 = xfd1; thread_arg->xfd1 = xfd1;
thread_arg->xfd2 = xfd2; thread_arg->xfd2 = xfd2;
Notice5("starting thread: dir=%d, reverseA=%d, reverseB=%d, xfd1->tag=%d, xfd2->tag=%d",
rw0, reverseA, reverseB, xfd1->tag, xfd2->tag);
if (xfd1->tag==XIO_TAG_DUAL) {
Notice4("xfd1: [%s, wfd=%d] %% [%s, rfd=%d]",
xfd1->dual.stream[1]->addrdesc->common_desc.defname,
xfd1->dual.stream[1]->wfd,
xfd1->dual.stream[0]->addrdesc->common_desc.defname,
xfd1->dual.stream[0]->rfd);
} else {
Notice3("xfd1: %s, wfd=%d, rfd=%d",
xfd1->stream.addrdesc->common_desc.defname,
xfd1->stream.wfd, xfd1->stream.rfd);
}
if (xfd2->tag==XIO_TAG_DUAL) {
Notice4("xfd2: [%s, wfd=%d] %% [%s, rfd=%d]",
xfd2->dual.stream[1]->addrdesc->common_desc.defname,
xfd2->dual.stream[1]->wfd,
xfd2->dual.stream[0]->addrdesc->common_desc.defname,
xfd2->dual.stream[0]->rfd);
} else {
Notice3("xfd2: %s, wfd=%d, rfd=%d",
xfd2->stream.addrdesc->common_desc.defname,
xfd2->stream.wfd, xfd2->stream.rfd);
}
Info5("pthread_create(%p, NULL, %s, {%d,%p,%p})",
&xfd0->stream.subthread,
(reverseA||(sfdB!=NULL)&&!reverseB)?"xioopenleftthenengine":"xioengine",
thread_arg->rw, thread_arg->xfd1, thread_arg->xfd2);
if ((_errno = if ((_errno =
Pthread_create(&xfd0->stream.subthread, NULL, Pthread_create(&xfd0->stream.subthread, NULL,
(reverseA||(sfdB!=NULL)&&!reverseB)?xioopenleftthenengine:xioengine, (reverseA||(sfdB!=NULL)&&!reverseB)?xioopenleftthenengine:xioengine,
thread_arg)) thread_arg))
!= 0) { != 0) {
Error4("pthread_create(%p, {}, xioengine, {%p,%p}): %s", Error3("pthread_create(%p, {}, xioengine, %p): %s",
&xfd0->stream.subthread, thread_arg->xfd1, thread_arg->xfd2, &xfd0->stream.subthread, thread_arg,
strerror(_errno)); strerror(_errno));
xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2); xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2);
free(thread_arg); return NULL; free(thread_arg); return NULL;
@ -830,7 +885,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
xfd2 = NULL; xfd2 = NULL;
/* open protocol part */ /* open protocol part */
if (xioopen_inter_dual(xfd0, dirs|flags) if (xioopen_inter_dual(xfd0, rw|flags)
< 0) { < 0) {
/*! close sub chain */ /*! close sub chain */
if (xfd0->stream.retry == 0 && !xfd0->stream.forever) { if (xfd0->stream.retry == 0 && !xfd0->stream.forever) {
@ -851,11 +906,12 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
void *xioopenleftthenengine(void *thread_void) { void *xioopenleftthenengine(void *thread_void) {
struct threadarg_struct *thread_arg = thread_void; struct threadarg_struct *thread_arg = thread_void;
int rw = thread_arg->rw;
xiofile_t *xfd1 = thread_arg->xfd1; xiofile_t *xfd1 = thread_arg->xfd1;
xiofile_t *xfd2 = thread_arg->xfd2; xiofile_t *xfd2 = thread_arg->xfd2;
/*! design a function with better interface */ /*! design a function with better interface */
if (xioopen_inter_dual(xfd1, XIO_RDWR|XIO_MAYCONVERT) < 0) { if (xioopen_inter_dual(xfd1, rw|XIO_MAYCONVERT|XIO_MAYCHILD) < 0) {
xioclose(xfd2); xioclose(xfd2);
xiofreefd(xfd1); xiofreefd(xfd1);
xiofreefd(xfd2); xiofreefd(xfd2);
@ -1120,7 +1176,7 @@ static int
tag = (mayright ? XIOADDR_INTER : XIOADDR_ENDPOINT); tag = (mayright ? XIOADDR_INTER : XIOADDR_ENDPOINT);
/* look for a matching entry in the list of address descriptions */ /* look for a matching entry in the list of address descriptions */
Debug5("searching record for \"%s\" with tag=%d, numparams=%d, leftdirs %d, rightdirs %d", Debug5("searching record for \"%s\" with tag=%d, numparams=%d, leftdir %d, rightdir %d",
addrdescs[0]->common_desc.defname, addrdescs[0]->common_desc.defname,
tag, sfd->argc-1, mayleft, mayright); tag, sfd->argc-1, mayleft, mayright);
while ((*addrdescs) != NULL) { while ((*addrdescs) != NULL) {
@ -1134,9 +1190,13 @@ static int
} }
if (addrdescs[0] == NULL) { if (addrdescs[0] == NULL) {
Error3("address \"%s...\" in %s context and with %d parameter(s) is not defined", if (tag == XIOADDR_ENDPOINT) {
sfd->argv[0], tag==XIOADDR_ENDPOINT?"endpoint":"intermediate", Error3("address \"%s...\" in endpoint context, leftdirs=%d, with %d parameter(s) is not available",
sfd->argc-1); sfd->argv[0], mayleft, sfd->argc-1);
} else {
Error4("address \"%s...\" in intermediate context, leftdirs=%d, rightdirs=%d, with %d parameter(s) is not available",
sfd->argv[0], mayleft, mayright, sfd->argc-1);
}
xiofreefd((xiofile_t *)sfd); return -1; xiofreefd((xiofile_t *)sfd); return -1;
} }
@ -1154,9 +1214,19 @@ static int
} }
sfd->tag = (*isleft + 1); sfd->tag = (*isleft + 1);
sfd->addrdesc = addrdescs[0]; sfd->addrdesc = addrdescs[0];
if (addrdescs[0]->common_desc.howtoshut != XIOSHUT_UNSPEC)
sfd->howtoshut = addrdescs[0]->common_desc.howtoshut; sfd->howtoshut = addrdescs[0]->common_desc.howtoshut;
if (addrdescs[0]->common_desc.howtoclose != XIOCLOSE_UNSPEC)
sfd->howtoclose = addrdescs[0]->common_desc.howtoclose; sfd->howtoclose = addrdescs[0]->common_desc.howtoclose;
if (tag == XIOADDR_ENDPOINT) {
Debug1("selected record with leftdirs %d",
addrdescs[0]->common_desc.leftdirs);
} else {
Debug2("selected record with leftdirs %d, rightdirs %d",
addrdescs[0]->common_desc.leftdirs,
addrdescs[0]->inter_desc.rightdirs);
}
return 0; return 0;
} }
@ -1170,17 +1240,10 @@ static int
if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) { if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) {
xfd->tag = XIO_TAG_RDONLY; xfd->tag = XIO_TAG_RDONLY;
xfd->stream.fdtype = FDTYPE_SINGLE;
} else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) { } else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) {
xfd->tag = XIO_TAG_WRONLY; xfd->tag = XIO_TAG_WRONLY;
xfd->stream.fdtype = FDTYPE_SINGLE;
} else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) { } else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) {
xfd->tag = XIO_TAG_RDWR; xfd->tag = XIO_TAG_RDWR;
if (xfd->stream.fd2 >= 0) {
xfd->stream.fdtype = FDTYPE_DOUBLE;
} else {
xfd->stream.fdtype = FDTYPE_SINGLE;
}
} else { } else {
Error1("invalid mode for address \"%s\"", xfd->stream.argv[0]); Error1("invalid mode for address \"%s\"", xfd->stream.argv[0]);
} }
@ -1201,10 +1264,8 @@ static int
addrdesc = &xfd->stream.addrdesc->endpoint_desc; addrdesc = &xfd->stream.addrdesc->endpoint_desc;
if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) { if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) {
xfd->tag = XIO_TAG_RDONLY; xfd->tag = XIO_TAG_RDONLY;
xfd->stream.fdtype = FDTYPE_SINGLE;
} else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) { } else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) {
xfd->tag = XIO_TAG_WRONLY; xfd->tag = XIO_TAG_WRONLY;
xfd->stream.fdtype = FDTYPE_SINGLE;
} else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) { } else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) {
xfd->tag = XIO_TAG_RDWR; xfd->tag = XIO_TAG_RDWR;
} else { } else {

View file

@ -1,5 +1,5 @@
/* source: xioopts.c */ /* source: xioopts.c */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for address options handling */ /* this file contains the source for address options handling */
@ -296,6 +296,7 @@ const struct optname optionnames[] = {
IF_TERMIOS("clocal", &opt_clocal) IF_TERMIOS("clocal", &opt_clocal)
IF_ANY ("cloexec", &opt_cloexec) IF_ANY ("cloexec", &opt_cloexec)
IF_ANY ("close", &opt_end_close) IF_ANY ("close", &opt_end_close)
IF_EXEC ("commtype", &opt_commtype)
#if WITH_EXT2 && defined(EXT2_COMPR_FL) #if WITH_EXT2 && defined(EXT2_COMPR_FL)
IF_ANY ("compr", &opt_ext2_compr) IF_ANY ("compr", &opt_ext2_compr)
#endif #endif
@ -497,8 +498,8 @@ const struct optname optionnames[] = {
IF_ANY ("f-setlkw", &opt_f_setlkw_wr) IF_ANY ("f-setlkw", &opt_f_setlkw_wr)
IF_ANY ("f-setlkw-rd", &opt_f_setlkw_rd) IF_ANY ("f-setlkw-rd", &opt_f_setlkw_rd)
IF_ANY ("f-setlkw-wr", &opt_f_setlkw_wr) IF_ANY ("f-setlkw-wr", &opt_f_setlkw_wr)
IF_EXEC ("fdin", &opt_fdin) IF_EXEC ("fdin", &opt_leftinfd)
IF_EXEC ("fdout", &opt_fdout) IF_EXEC ("fdout", &opt_leftoutfd)
#ifdef FFDLY #ifdef FFDLY
# ifdef FF0 # ifdef FF0
IF_TERMIOS("ff0", &opt_ff0) IF_TERMIOS("ff0", &opt_ff0)
@ -805,6 +806,10 @@ const struct optname optionnames[] = {
#ifdef O_LARGEFILE #ifdef O_LARGEFILE
IF_OPEN ("largefile", &opt_o_largefile) IF_OPEN ("largefile", &opt_o_largefile)
#endif #endif
IF_EXEC ("left", &opt_leftfd)
IF_EXEC ("leftfd", &opt_leftfd)
IF_EXEC ("leftinfd", &opt_leftinfd)
IF_EXEC ("leftoutfd", &opt_leftoutfd)
#if WITH_LIBWRAP #if WITH_LIBWRAP
IF_IPAPP ("libwrap", &opt_tcpwrappers) IF_IPAPP ("libwrap", &opt_tcpwrappers)
#endif #endif
@ -1195,6 +1200,12 @@ const struct optname optionnames[] = {
#ifdef TCP_RFC1323 #ifdef TCP_RFC1323
IF_TCP ("rfc1323", &opt_tcp_rfc1323) IF_TCP ("rfc1323", &opt_tcp_rfc1323)
#endif #endif
IF_EXEC ("right", &opt_rightfd)
IF_EXEC ("rightfd", &opt_rightfd)
IF_EXEC ("rightin", &opt_rightinfd)
IF_EXEC ("rightinfd", &opt_rightinfd)
IF_EXEC ("rightout", &opt_rightoutfd)
IF_EXEC ("rightoutfd",&opt_rightoutfd)
#ifdef IP_ROUTER_ALERT #ifdef IP_ROUTER_ALERT
IF_IP ("routeralert", &opt_ip_router_alert) IF_IP ("routeralert", &opt_ip_router_alert)
#endif #endif
@ -1272,6 +1283,8 @@ const struct optname optionnames[] = {
IF_SOCKET ("setsockopt-string", &opt_setsockopt_string) IF_SOCKET ("setsockopt-string", &opt_setsockopt_string)
IF_ANY ("setuid", &opt_setuid) IF_ANY ("setuid", &opt_setuid)
IF_ANY ("setuid-early", &opt_setuid_early) IF_ANY ("setuid-early", &opt_setuid_early)
IF_ANY ("shut-close", &opt_shut_close)
IF_ANY ("shut-down", &opt_shut_down)
IF_ANY ("shut-none", &opt_shut_none) IF_ANY ("shut-none", &opt_shut_none)
#if WITH_EXEC || WITH_SYSTEM #if WITH_EXEC || WITH_SYSTEM
IF_ANY ("sid", &opt_setsid) IF_ANY ("sid", &opt_setsid)
@ -3964,10 +3977,10 @@ mc:addr
#endif #endif
#if HAVE_STRUCT_IP_MREQN #if HAVE_STRUCT_IP_MREQN
if (Setsockopt(xfd->fd1, opt->desc->major, opt->desc->minor, if (Setsockopt(xfd->rfd, opt->desc->major, opt->desc->minor,
&ip4_mreqn.mreqn, sizeof(ip4_mreqn.mreqn)) < 0) { &ip4_mreqn.mreqn, sizeof(ip4_mreqn.mreqn)) < 0) {
Error8("setsockopt(%d, %d, %d, {0x%08x,0x%08x,%d}, "F_Zu"): %s", Error8("setsockopt(%d, %d, %d, {0x%08x,0x%08x,%d}, "F_Zu"): %s",
xfd->fd1, opt->desc->major, opt->desc->minor, xfd->rfd, opt->desc->major, opt->desc->minor,
ip4_mreqn.mreqn.imr_multiaddr.s_addr, ip4_mreqn.mreqn.imr_multiaddr.s_addr,
ip4_mreqn.mreqn.imr_address.s_addr, ip4_mreqn.mreqn.imr_address.s_addr,
ip4_mreqn.mreqn.imr_ifindex, ip4_mreqn.mreqn.imr_ifindex,
@ -4017,10 +4030,10 @@ mc:addr
ip6_mreq.ipv6mr_interface = htonl(0); ip6_mreq.ipv6mr_interface = htonl(0);
} }
if (Setsockopt(xfd->fd1, opt->desc->major, opt->desc->minor, if (Setsockopt(xfd->rfd, opt->desc->major, opt->desc->minor,
&ip6_mreq, sizeof(ip6_mreq)) < 0) { &ip6_mreq, sizeof(ip6_mreq)) < 0) {
Error6("setsockopt(%d, %d, %d, {...,0x%08x}, "F_Zu"): %s", Error6("setsockopt(%d, %d, %d, {...,0x%08x}, "F_Zu"): %s",
xfd->fd1, opt->desc->major, opt->desc->minor, xfd->rfd, opt->desc->major, opt->desc->minor,
ip6_mreq.ipv6mr_interface, ip6_mreq.ipv6mr_interface,
sizeof(ip6_mreq), sizeof(ip6_mreq),
strerror(errno)); strerror(errno));
@ -4070,29 +4083,36 @@ int applyopts_signal(struct single *xfd, struct opt *opts) {
/* apply remaining options to file descriptor, and tell us if something is /* apply remaining options to file descriptor, and tell us if something is
still unused */ still unused */
int _xio_openlate(struct single *fd, struct opt *opts) { int _xio_openlate(struct single *xfd, struct opt *opts) {
int fd;
int numleft; int numleft;
int result; int result;
if (xfd->rfd >= 0) {
fd = xfd->rfd;
} else {
fd = xfd->wfd;
}
_xioopen_setdelayeduser(); _xioopen_setdelayeduser();
if ((result = applyopts(fd->fd1, opts, PH_LATE)) < 0) { if ((result = applyopts(fd, opts, PH_LATE)) < 0) {
return result; return result;
} }
#if 0 /*! need to copy opts before previous statement! */ #if 0 /*! need to copy opts before previous statement! */
if (fd->fdtype == FDTYPE_DOUBLE) { if (xfd->fdtype == FDTYPE_DOUBLE) {
if ((result = applyopts(fd->fd2, opts, PH_LATE)) < 0) { if ((result = applyopts(fd, opts, PH_LATE)) < 0) {
return result; return result;
} }
} }
#endif #endif
if ((result = applyopts_single(fd, opts, PH_LATE)) < 0) { if ((result = applyopts_single(xfd, opts, PH_LATE)) < 0) {
return result; return result;
} }
if ((result = applyopts(fd->fd1, opts, PH_LATE2)) < 0) { if ((result = applyopts(fd, opts, PH_LATE2)) < 0) {
return result; return result;
} }
/*! need to apply to fd2 too! */ /*! need to apply to wfd too! */
if ((numleft = leftopts(opts)) > 0) { if ((numleft = leftopts(opts)) > 0) {
showleft(opts); showleft(opts);

View file

@ -1,5 +1,5 @@
/* source: xioopts.h */ /* source: xioopts.h */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger 2001-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xioopts_h_included #ifndef __xioopts_h_included
@ -235,6 +235,7 @@ enum e_optcode {
/*OPT_CIBAUD,*/ /* termios.c_cflag */ /*OPT_CIBAUD,*/ /* termios.c_cflag */
OPT_CLOCAL, /* termios.c_cflag */ OPT_CLOCAL, /* termios.c_cflag */
OPT_CLOEXEC, OPT_CLOEXEC,
OPT_COMMTYPE, /* exec/system communication type */
OPT_CONNECT_TIMEOUT, /* socket connect */ OPT_CONNECT_TIMEOUT, /* socket connect */
OPT_COOL_WRITE, OPT_COOL_WRITE,
OPT_CR, /* customized */ OPT_CR, /* customized */
@ -288,8 +289,9 @@ enum e_optcode {
OPT_EXT2_NOTAIL, OPT_EXT2_NOTAIL,
OPT_EXT2_DIRSYNC, OPT_EXT2_DIRSYNC,
OPT_EXT2_TOPDIR, OPT_EXT2_TOPDIR,
OPT_FDIN, OPT_LEFTFD,
OPT_FDOUT, OPT_LEFTINFD,
OPT_LEFTOUTFD,
#ifdef FFDLY #ifdef FFDLY
# ifdef FF0 # ifdef FF0
OPT_FF0, /* termios.c_oflag */ OPT_FF0, /* termios.c_oflag */
@ -573,6 +575,9 @@ enum e_optcode {
OPT_RES_STAYOPEN, /* resolver(3) */ OPT_RES_STAYOPEN, /* resolver(3) */
OPT_RES_USEVC, /* resolver(3) */ OPT_RES_USEVC, /* resolver(3) */
OPT_RETRY, OPT_RETRY,
OPT_RIGHTFD, /* inter exec, system */
OPT_RIGHTINFD, /* inter exec, system */
OPT_RIGHTOUTFD, /* inter exec, system */
OPT_SANE, /* termios */ OPT_SANE, /* termios */
OPT_SCTP_MAXSEG, OPT_SCTP_MAXSEG,
OPT_SCTP_MAXSEG_LATE, OPT_SCTP_MAXSEG_LATE,
@ -592,6 +597,8 @@ enum e_optcode {
OPT_SETSOCKOPT_STRING, OPT_SETSOCKOPT_STRING,
OPT_SETUID, OPT_SETUID,
OPT_SETUID_EARLY, OPT_SETUID_EARLY,
OPT_SHUT_CLOSE,
OPT_SHUT_DOWN,
OPT_SHUT_NONE, OPT_SHUT_NONE,
OPT_SIGHUP, OPT_SIGHUP,
OPT_SIGINT, OPT_SIGINT,

View file

@ -32,6 +32,7 @@ xioopts_t xioopts = {
{0,500000}, /* closwait */ {0,500000}, /* closwait */
false, /* lefttoright */ false, /* lefttoright */
false, /* righttoleft */ false, /* righttoleft */
0, /* pipetype: two unidirectional socketpairs */
} ; } ;
xioopts_t *xioparams = &xioopts; xioopts_t *xioparams = &xioopts;

View file

@ -158,7 +158,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
msgh.msg_controllen = sizeof(ctrlbuff); msgh.msg_controllen = sizeof(ctrlbuff);
#endif #endif
if (xiogetpacketsrc(pipe->fd1, &msgh) < 0) { if (xiogetpacketsrc(pipe->rfd, &msgh) < 0) {
return -1; return -1;
} }
do { do {
@ -350,7 +350,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
msgh.msg_controllen = sizeof(ctrlbuff); msgh.msg_controllen = sizeof(ctrlbuff);
#endif #endif
if (xiogetpacketsrc(pipe->fd1, &msgh) < 0) { if (xiogetpacketsrc(pipe->rfd, &msgh) < 0) {
return -1; return -1;
} }
xiodopacketinfo(&msgh, true, false); xiodopacketinfo(&msgh, true, false);

View file

@ -52,6 +52,40 @@ int xioshutdown(xiofile_t *sock, int how) {
/* here handle special shutdown functions */ /* here handle special shutdown functions */
switch (sock->stream.howtoshut) { switch (sock->stream.howtoshut) {
#if WITH_PTY
case XIOSHUT_PTYEOF:
{
struct termios termarg;
int result;
Debug1("tcdrain(%d)", sock->stream.wfd);
result = tcdrain(sock->stream.wfd);
Debug1("tcdrain() -> %d", result);
if (Tcgetattr(sock->stream.wfd, &termarg) < 0) {
Error3("tcgetattr(%d, %p): %s",
sock->stream.wfd, &termarg, strerror(errno));
}
#if 0
/* these settings might apply to data still in the buff (despite the
TCSADRAIN */
termarg.c_iflag |= (IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
termarg.c_oflag |= OPOST;
termarg.c_lflag |= (/*ECHO | ECHONL |*/ ICANON | ISIG | IEXTEN);
//termarg.c_cflag |= (PARENB);
#else
termarg.c_lflag |= ICANON;
#endif
if (Tcsetattr(sock->stream.wfd, TCSADRAIN, &termarg) < 0) {
Error3("tcsetattr(%d, TCSADRAIN, %p): %s",
sock->stream.wfd, &termarg, strerror(errno));
}
if (Write(sock->stream.wfd, &termarg.c_cc[VEOF], 1) < 1) {
Warn3("write(%d, 0%o, 1): %s",
sock->stream.wfd, termarg.c_cc[VEOF], strerror(errno));
}
}
return 0;
#endif /* WITH_PTY */
#if WITH_OPENSSL #if WITH_OPENSSL
case XIOSHUT_OPENSSL: case XIOSHUT_OPENSSL:
sycSSL_shutdown(sock->stream.para.openssl.ssl); sycSSL_shutdown(sock->stream.para.openssl.ssl);
@ -120,9 +154,9 @@ int xioshutdown(xiofile_t *sock, int how) {
case XIOREAD_STREAM: case XIOREAD_STREAM:
case XIODATA_2PIPE: case XIODATA_2PIPE:
if (Close(sock->stream.fd1) < 0) { if (Close(sock->stream.rfd) < 0) {
Info2("close(%d): %s", Info2("close(%d): %s",
sock->stream.fd1, strerror(errno)); sock->stream.rfd, strerror(errno));
} }
break; break;
} }
@ -132,11 +166,7 @@ int xioshutdown(xiofile_t *sock, int how) {
/* shutdown write channel */ /* shutdown write channel */
int fd; int fd;
if (sock->stream.fdtype == FDTYPE_DOUBLE) { fd = sock->stream.wfd;
fd = sock->stream.fd2;
} else {
fd = sock->stream.fd1;
}
switch (sock->stream.howtoshut & XIOSHUTWR_MASK) { switch (sock->stream.howtoshut & XIOSHUTWR_MASK) {
@ -183,6 +213,7 @@ int xioshutdown(xiofile_t *sock, int how) {
Error1("xioshutdown(): unhandled howtoshut=0x%x during SHUT_WR", Error1("xioshutdown(): unhandled howtoshut=0x%x during SHUT_WR",
sock->stream.howtoshut&XIOSHUTWR_MASK); sock->stream.howtoshut&XIOSHUTWR_MASK);
} }
sock->stream.wfd = -1;
} }
return result; return result;

View file

@ -1,14 +1,16 @@
/* $Id$ */ /* $Id$ */
/* Copyright Gerhard Rieger 2007 */ /* Copyright Gerhard Rieger 2007-2009 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this is the source of the internal xiosocketpair function */ /* this is the source of the internal xiosocketpair function */
#include "xiosysincludes.h" #include "xiosysincludes.h"
#include "sycls.h" #include "sycls.h"
#include "compat.h"
#include "error.h" #include "error.h"
#include "xio.h" #include "xio.h"
#if defined(HAVE_DEV_PTMX) #if defined(HAVE_DEV_PTMX)
# define PTMX "/dev/ptmx" /* Linux */ # define PTMX "/dev/ptmx" /* Linux */
#elif HAVE_DEV_PTC #elif HAVE_DEV_PTC
@ -17,84 +19,10 @@
#define MAXPTYNAMELEN 64 #define MAXPTYNAMELEN 64
/* how: 0...socketpair; 1...pipes pair; 2...pty (master, slave) int xiopty(int useptmx, int *ttyfdp, int *ptyfdp) {
how==0: var args (int)domain, (int)type, (int)protocol int ttyfd, ptyfd = -1;
how==1: no var args
how==2: var args (int)useptmx
returns -1 on error or 0 on success */
int xiosocketpair2(xiofile_t **xfd1p, xiofile_t **xfd2p, int how, ...) {
va_list ap;
xiofile_t *xfd1, *xfd2;
int result = 0;
if ((xfd1 = xioallocfd()) == NULL) {
return -1;
}
if ((xfd2 = xioallocfd()) == NULL) {
xiofreefd(xfd1);
return -1;
}
switch (how) {
case 0: /* socketpair */
{
int sv[2];
int domain, type, protocol;
va_start(ap, how);
domain = va_arg(ap, int);
type = va_arg(ap, int);
protocol = va_arg(ap, int);
va_end(ap);
if (Socketpair(domain, type, protocol, sv) < 0) {
Error5("socketpair(%d, %d, %d, %p): %s",
domain, type, protocol, sv, strerror(errno));
xiofreefd(xfd1); xiofreefd(xfd2);
return -1;
}
assert(xfd1->stream.fdtype == FDTYPE_SINGLE);
xfd1->stream.fd1 = sv[0];
assert(xfd2->stream.fdtype == FDTYPE_SINGLE);
xfd2->stream.fd1 = sv[1];
}
break;
case 1:
{
int filedes1[2], filedes2[2];
if (Pipe(filedes1) < 0) {
Error2("pipe(%p): %s", filedes1, strerror(errno));
xiofreefd(xfd1); xiofreefd(xfd2);
return -1;
}
if (Pipe(filedes2) < 0) {
Error2("pipe(%p): %s", filedes2, strerror(errno));
xiofreefd(xfd1); xiofreefd(xfd2);
Close(filedes1[0]); Close(filedes1[1]);
return -1;
}
xfd1->stream.fd1 = filedes1[0];
xfd1->stream.fd2 = filedes2[1];
xfd1->stream.fdtype = FDTYPE_DOUBLE;
xfd1->stream.dtype = XIODATA_2PIPE;
xfd2->stream.fd1 = filedes2[0];
xfd2->stream.fd2 = filedes1[1];
xfd2->stream.fdtype = FDTYPE_DOUBLE;
xfd2->stream.dtype = XIODATA_2PIPE;
}
break;
#if HAVE_DEV_PTMX || HAVE_DEV_PTC
case 2: /* pty (master, slave) */
{
int useptmx;
char ptyname[MAXPTYNAMELEN]; char ptyname[MAXPTYNAMELEN];
int ptyfd = -1, ttyfd; struct termios termarg;
va_start(ap, how);
useptmx = va_arg(ap, int);
va_end(ap);
if (useptmx) { if (useptmx) {
if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) { if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) {
@ -165,22 +93,314 @@ int xiosocketpair2(xiofile_t **xfd1p, xiofile_t **xfd2p, int how, ...) {
Notice1("PTY is %s", ptyname); Notice1("PTY is %s", ptyname);
} }
#endif /* HAVE_OPENPTY */ #endif /* HAVE_OPENPTY */
assert(xfd1->stream.fdtype == FDTYPE_SINGLE);
xfd1->stream.fd1 = ttyfd;
assert(xfd2->stream.fdtype == FDTYPE_SINGLE);
xfd2->stream.fd1 = ptyfd;
}
break;
#endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */
default: if (Tcgetattr(ttyfd, &termarg) < 0) {
Error1("undefined socketpair mechanism %d", how); Error3("tcgetattr(%d, %p): %s",
xiofreefd(xfd1); xiofreefd(xfd2); ttyfd, &termarg, strerror(errno));
return -1; }
#if 0
cfmakeraw(&termarg);
#else
/*!!! share code with xioopts.c raw,echo=0 */
termarg.c_iflag &=
~(IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF
#ifdef IUCLC
|IUCLC
#endif
|IXANY|IMAXBEL);
termarg.c_iflag |= (0);
termarg.c_oflag &= ~(OPOST);
termarg.c_oflag |= (0);
termarg.c_cflag &= ~(0);
termarg.c_cflag |= (0);
termarg.c_lflag &= ~(ECHO|ECHONL|ISIG|ICANON
#ifdef XCASE
|XCASE
#endif
);
termarg.c_lflag |= (0);
termarg.c_cc[VMIN] = 1;
termarg.c_cc[VTIME] = 0;
#endif
if (Tcsetattr(ttyfd, TCSADRAIN, &termarg) < 0) {
Error3("tcsetattr(%d, TCSADRAIN, %p): %s",
ttyfd, &termarg, strerror(errno));
} }
*xfd1p = xfd1; *ttyfdp = ttyfd;
*xfd2p = xfd2; *ptyfdp = ptyfd;
return 0;
}
/* generates a socket pair; supports not only PF_UNIX but also PF_INET */
int xiosocketpair2(int pf, int socktype, int protocol, int sv[2]) {
int result;
switch (pf) {
struct sockaddr_in ssin, csin, xsin; /* server, client, compare */
socklen_t cslen, xslen;
int sconn, slist, sserv; /* socket FDs */
case PF_UNIX:
result = Socketpair(pf, socktype, protocol, sv);
if (result < 0) {
Error5("socketpair(%d, %d, %d, %p): %s",
pf, socktype, protocol, sv, strerror(errno));
return -1;
}
break;
#if LATER
case PF_INET:
#if 1 /*!!! Linux */
ssin.sin_family = pf;
ssin.sin_port = htons(1024+random()%(65536-1024));
ssin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
#endif /* */
if ((s = Socket(pf, socktype, protocol)) < 0) {
Error4("socket(%d, %d, %d): %s",
pf, socktype, protocol, strerror(errno));
}
if (Bind(s, (struct sockaddr *)&ssin, sizeof(ssin)) < 0) {
Error6("bind(%d, {%u, 0x%x:%u}, "F_Zu"): %s",
s, ssin.sin_family, ssin.sin_addr.s_addr, ssin.sin_port,
sizeof(ssin), strerror(errno));
}
if (Connect(s, (struct sockaddr *)&ssin, sizeof(ssin)) < 0) {
Error6("connect(%d, {%u, 0x%x:%u}, "F_Zu"): %s",
s, ssin.sin_family, ssin.sin_addr.s_addr, ssin.sin_port,
sizeof(ssin), strerror(errno));
return -1;
}
break;
#endif /* LATER */
case PF_INET:
ssin.sin_family = pf;
ssin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if ((slist = Socket(pf, socktype, protocol)) < 0) {
Error4("socket(%d, %d, %d): %s",
pf, socktype, protocol, strerror(errno));
}
while (true) { /* find a port we can bind to */
ssin.sin_port = htons(1024+random()%(65536-1024));
if (Bind(slist, (struct sockaddr *)&ssin, sizeof(ssin)) == 0) break;
if (errno == EADDRINUSE) {
Info6("bind(%d, {%u, 0x%x:%u}, "F_Zu"): %s",
slist, ssin.sin_family, ssin.sin_addr.s_addr,
ntohs(ssin.sin_port), sizeof(ssin), strerror(errno));
continue;
}
Error6("bind(%d, {%u, 0x%x:%u}, "F_Zu"): %s",
slist, ssin.sin_family, ssin.sin_addr.s_addr, ssin.sin_port,
sizeof(ssin), strerror(errno));
Close(slist);
return -1;
}
Listen(slist, 0);
if ((sconn = Socket(pf, socktype, protocol)) < 0) {
Error4("socket(%d, %d, %d): %s",
pf, socktype, protocol, strerror(errno));
Close(slist); return -1;
}
/* for testing race condition: Sleep(30); */
if (Connect(sconn, (struct sockaddr *)&ssin, sizeof(ssin)) < 0) {
Error6("connect(%d, {%u, 0x%x:%u}, "F_Zu"): %s",
sconn, ssin.sin_family, ssin.sin_addr.s_addr,
ntohs(ssin.sin_port),
sizeof(ssin), strerror(errno));
Close(slist); Close(sconn); return -1;
}
cslen = sizeof(csin);
if (Getsockname(sconn, (struct sockaddr *)&csin, &cslen) < 0) {
Error4("getsockname(%d, %p, %p): %s",
sconn, &csin, &cslen, strerror(errno));
Close(slist); Close(sconn); return -1;
}
do {
xslen = sizeof(xsin);
if ((sserv = Accept(slist, (struct sockaddr *)&xsin, &xslen)) < 0) {
Error4("accept(%d, %p, {"F_Zu"}): %s",
slist, &csin, sizeof(xslen), strerror(errno));
Close(slist); Close(sconn); return -1;
}
if (!memcmp(&csin, &xsin, cslen)) {
break; /* expected connection */
}
Warn4("unexpected connection to 0x%lx:%hu from 0x%lx:%hu",
ntohl(ssin.sin_addr.s_addr), ntohs(ssin.sin_port),
ntohl(xsin.sin_addr.s_addr), ntohs(xsin.sin_port));
} while (true);
Close(slist);
sv[0] = sconn;
sv[1] = sserv;
break;
default:
Error1("xiosocketpair2(): pf=%u not implemented", pf);
return -1;
}
return 0;
}
/*
dual should only be != 0 when both directions are used
returns 0 on success
*/
int xiocommpair(int commtype, bool lefttoright, bool righttoleft,
int dual, xiofd_t *left, xiofd_t *right, ...) {
va_list ap;
int domain, socktype, protocol;
int useptmx;
/* arrays can be used with pipe(2) and socketpair(2): */
int svlr[2] = {-1, -1}; /* left to right: rfd, wfd */
int svrl[2] = {-1, -1}; /* right to left: rfd, wfd */
/* get related parameters from parameter list */
switch (commtype) {
case XIOCOMM_SOCKETPAIR:
case XIOCOMM_SOCKETPAIRS:
va_start(ap, right);
domain = va_arg(ap, int);
socktype = va_arg(ap, int);
protocol = va_arg(ap, int);
va_end(ap);
break;
case XIOCOMM_PTY:
case XIOCOMM_PTYS:
va_start(ap, right);
useptmx = va_arg(ap, int);
va_end(ap);
break;
default:
break;
}
switch (commtype) {
default: /* unspec */
Warn1("internal: undefined communication type %d, defaulting to 0",
commtype);
commtype = 0;
/*PASSTHROUGH*/
case XIOCOMM_SOCKETPAIRS: /* two socketpairs - the default */
if (lefttoright) {
if (Socketpair(domain, socktype, protocol, svlr) < 0) {
Error5("socketpair(%d, %d, %d, %p): %s",
domain, socktype, protocol, svlr, strerror(errno));
}
Shutdown(svlr[0], SHUT_WR);
}
if (righttoleft) {
if (Socketpair(domain, socktype, protocol, svrl) < 0) {
Error5("socketpair(%d, %d, %d, %p): %s",
domain, socktype, protocol, svrl, strerror(errno));
}
Shutdown(svrl[0], SHUT_WR);
}
left->single = right->single = false;
left->dtype = right->dtype = XIODATA_STREAM;
left->howtoshut = right->howtoshut = XIOSHUT_DOWN;
left->howtoclose = right->howtoclose = XIOCLOSE_CLOSE;
break;
case XIOCOMM_PTYS: /* two ptys in raw mode, EOF in canonical mode */
if (lefttoright) {
if (xiopty(useptmx, &svlr[0], &svlr[1]) < 0) return -1;
/* pty is write side, interpretes ^D in canonical mode */
}
if (righttoleft) {
if (xiopty(useptmx, &svrl[0], &svrl[1]) < 0) return -1;
}
left->single = right->single = false;
left->dtype = right->dtype = XIODATA_PTY;
left->howtoshut = right->howtoshut = XIOSHUT_PTYEOF;
left->howtoclose = right->howtoclose = XIOCLOSE_CLOSE;
break;
case XIOCOMM_SOCKETPAIR: /* one socketpair */
if (Socketpair(domain, socktype, protocol, svlr) < 0) {
Error5("socketpair(%d %d %d, %p): %s",
domain, socktype, protocol, svlr, strerror(errno));
return -1;
}
left->single = right->single = true;
left->dtype = right->dtype = XIODATA_STREAM;
left->howtoshut = right->howtoshut = XIOSHUT_DOWN;
left->howtoclose = right->howtoclose = XIOCLOSE_CLOSE;
break;
case XIOCOMM_PTY: /* one pty in raw mode, EOF in canonical mode */
if (xiopty(useptmx, &svlr[0], &svlr[1]) < 0) return -1;
left->single = right->single = true;
left->dtype = right->dtype = XIODATA_PTY;
left->howtoshut = XIOSHUT_PTYEOF;
right->howtoshut = XIOSHUT_CLOSE;
left->howtoclose = right->howtoclose = XIOCLOSE_CLOSE;
break;
case XIOCOMM_PIPES: /* two pipes */
if (lefttoright) {
if (Pipe(svlr) < 0) {
Error2("pipe(%p): %s", svlr, strerror(errno));
return -1;
}
}
if (righttoleft) {
if (Pipe(svrl) < 0) {
Error2("pipe(%p): %s", svrl, strerror(errno));
return -1;
}
}
left->single = right->single = false;
left->dtype = right->dtype = XIODATA_STREAM;
left->howtoshut = right->howtoshut = XIOSHUT_CLOSE;
left->howtoclose = right->howtoclose = XIOCLOSE_CLOSE;
break;
case XIOCOMM_TCP:
case XIOCOMM_TCP4: /* one TCP/IPv4 socket pair */
if (xiosocketpair2(PF_INET, SOCK_STREAM, 0, svlr) < 0) {
Error2("socketpair(PF_UNIX, PF_STREAM, 0, %p): %s",
svlr, strerror(errno));
return -1;
}
left->single = right->single = true;
left->dtype = right->dtype = XIODATA_STREAM;
left->howtoshut = right->howtoshut = XIOSHUT_DOWN;
left->howtoclose = right->howtoclose = XIOCLOSE_CLOSE;
break;
}
if (dual && left->single) {
/* one pair */
/* dual; we use different FDs for the channels to avoid conflicts
(happened in dual exec) */
if ((svrl[1] = Dup(svlr[0])) < 0) {
Error2("dup(%d): %s", svrl[0], strerror(errno));
return -1;
}
if ((svrl[0] = Dup(svlr[1])) < 0) {
Error2("dup(%d): %s", svlr[1], strerror(errno));
return -1;
}
} else if (left->single) {
svrl[1] = svlr[0];
svrl[0] = svlr[1];
}
/* usually they are not to be passed to exec'd child processes */
if (lefttoright) {
Fcntl_l(svlr[0], F_SETFD, 1);
Fcntl_l(svlr[1], F_SETFD, 1);
}
if (righttoleft && (!left->single || dual)) {
Fcntl_l(svrl[0], F_SETFD, 1);
Fcntl_l(svrl[1], F_SETFD, 1);
}
left->rfd = svrl[0];
left->wfd = svlr[1];
right->rfd = svlr[0];
right->wfd = svrl[1];
Notice4("xiocommpair() -> [%d:%d], [%d:%d]",
left->rfd, left->wfd, right->rfd, right->wfd);
return 0; return 0;
} }