mirror of
https://github.com/moparisthebest/socat
synced 2024-11-15 21:45:05 -05:00
added inter address exec and system modules
This commit is contained in:
parent
b53a9afba7
commit
515c305a7f
13
Makefile.in
13
Makefile.in
@ -1,5 +1,5 @@
|
||||
# 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
|
||||
|
||||
# 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 \
|
||||
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
|
||||
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 \
|
||||
Config/Makefile.SunOS-5-10 Config/config.SunOS-5-10.h \
|
||||
Config/Makefile.FreeBSD-6-1 Config/config.FreeBSD-6-1.h \
|
||||
|
68
bin/cat2.sh
Executable file
68
bin/cat2.sh
Executable 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
53
bin/predialog.sh
Executable 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
320
doc/socat-addresschain.html
Normal 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 > to forward, and < 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
|
||||
ˆ.
|
||||
</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:<port> rwb groups=FD,SOCKET,LISTEN,CHILD,RETRY,RANGE,IP4,IP6,TCP,OPENSSL</pre>
|
||||
</p>
|
||||
<p>The <tt>rwb 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>ˆ</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
114
doc/socat-exec.html
Normal 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>
|
383
doc/socat.yo
383
doc/socat.yo
@ -10,7 +10,7 @@ def(Filan)(0)(bf(Filan))
|
||||
def(procan)(0)(bf(procan))
|
||||
def(Procan)(0)(bf(Procan))
|
||||
|
||||
manpage(socat)(1)(Oct 2008)()()
|
||||
manpage(socat)(1)(Apr 2009)()()
|
||||
|
||||
whenhtml(
|
||||
label(CONTENTS)
|
||||
@ -38,7 +38,7 @@ manpagename(socat) (Multipurpose relay (SOcket CAT))
|
||||
|
||||
label(SYNOPSIS)
|
||||
manpagesynopsis()
|
||||
tt(socat [options] <address> <address>)nl()
|
||||
tt(socat [options] <address-chain> <address-chain>)nl()
|
||||
tt(socat -V)nl()
|
||||
tt(socat -h[h[h]] | -?[?[?]])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
|
||||
from a large set of different types of data sinks and sources
|
||||
(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.
|
||||
It might be one of the tools that one `has already needed'.
|
||||
|
||||
Filan() is a utility that prints information about its active file
|
||||
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
|
||||
initialized.
|
||||
|
||||
During the em(open) phase, socat() opens the first address and afterwards the
|
||||
second address. These steps are usually blocking; thus, especially for complex address types like socks,
|
||||
connection requests or authentication dialogs must be completed before the next
|
||||
step is started.
|
||||
During the em(open) phase, socat() opens the first address chain and afterwards
|
||||
the second address chain. These steps are usually blocking; thus, connection
|
||||
requests or authentication dialogs must be completed before the next step is
|
||||
started.
|
||||
|
||||
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)
|
||||
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
|
||||
descriptor of the other stream, then continues waiting for more data in both
|
||||
directions.
|
||||
@ -98,7 +97,7 @@ link(address options)(ADDRESS_OPTIONS) that are used as parts of link(address sp
|
||||
startdit()
|
||||
dit(bf(tt(-V)))
|
||||
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
|
||||
types, and exit.
|
||||
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
|
||||
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 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.
|
||||
label(option_t)dit(bf(tt(-t))tt(<timeout>))
|
||||
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
|
||||
before terminating. Default is 0.5 seconds. This timeout only applies to
|
||||
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.
|
||||
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
|
||||
(no data arrived, no interrupt occurred...) then it terminates.
|
||||
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)))
|
||||
Use IP version 6 in case that the addresses do not implicitly or explicitly
|
||||
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()
|
||||
|
||||
|
||||
label(ADDRESS_SPECIFICATIONS)
|
||||
manpagesection(ADDRESS SPECIFICATIONS)
|
||||
|
||||
With the address command line arguments, the user gives socat() instructions and
|
||||
the necessary information for establishing the byte streams.
|
||||
From the two em(address chain) command line argument, socat() gets instructions
|
||||
and the necessary information for establishing the byte streams.
|
||||
|
||||
An address specification usually consists 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 ','.
|
||||
An address chain consists of a sequence of zero or more em(inter addresses) and
|
||||
one em(endpoint address), all separated by '|'.
|
||||
|
||||
The keyword specifies the address type (e.g., TCP4, OPEN, EXEC). For some
|
||||
keywords there exist synonyms ('-' for STDIO, TCP for TCP4). Keywords are case
|
||||
insensitive.
|
||||
COMMENT(All addresses are either the first in a chain or have a left neighbor.)
|
||||
|
||||
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:
|
||||
Address specifications starting with a number are assumed to be FD (raw file
|
||||
descriptor) addresses;
|
||||
if a '/' is found before the first ':' or ',', GOPEN (generic file open) is
|
||||
assumed.
|
||||
An address specification starting with a number is assumed to be an
|
||||
link(FD)(ADDRESS_FD) (raw file descriptor) address;
|
||||
if a '/' is found before the first ':' or ',', link(GOPEN)(ADDRESS_GOPEN)
|
||||
(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
|
||||
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
|
||||
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.
|
||||
For filtering the options that are useful with an address
|
||||
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)
|
||||
Address specifications following the above schema are also called em(single)
|
||||
address specifications.
|
||||
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
|
||||
data, and the
|
||||
second address for writing data. There is no way to specify an option only once
|
||||
for being applied to both single addresses.
|
||||
Two single addresses can be combined with "%" to form a em(dual) type
|
||||
address. Here, the first address is used by socat() for transferring data from
|
||||
left to right, and the second address from right to left. Of course this
|
||||
requires bidirectional context, while both single addresses are integrated
|
||||
unidirectionally.
|
||||
|
||||
Usually, addresses are opened in read/write
|
||||
mode. When an address is part of a dual address specification, or when
|
||||
link(option -u)(option_u) or link(-U)(option_U) is used, an address might be
|
||||
used only for reading or for writing. Considering this is important with some
|
||||
address types.
|
||||
label(ADDRESS_REVERSE)
|
||||
Inter addresses can be used in reverse mode by prefixing them with the
|
||||
character '^' (caret). That means that the right side of the inter address is
|
||||
connected to its left neighbor and its left side to its right neighbor.<br>
|
||||
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.
|
||||
If one of the characters ( { [ ' is found, the corresponding closing
|
||||
character - ) } ] ' - is looked for; they may also be nested. Within these
|
||||
constructs, socats special characters and strings : , !! are not handled
|
||||
specially. All those characters and strings can be escaped with \ or within ""
|
||||
constructs, socat()s special characters and strings ':' ',' '%' are not handled
|
||||
specially. All those characters and strings can be escaped with \ or within "".
|
||||
|
||||
label(ADDRESS_TYPES)
|
||||
manpagesection(ADDRESS TYPES)
|
||||
@ -276,17 +317,26 @@ label(ADDRESS_CREAT)dit(bf(tt(CREATE:<filename>)))
|
||||
link(append)(OPTION_APPEND)nl()
|
||||
See also: link(OPEN)(ADDRESS_OPEN), link(GOPEN)(ADDRESS_GOPEN)
|
||||
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
|
||||
and invokes the specified program with code(execvp()).
|
||||
link(<command-line>)(TYPE_COMMAND_LINE) is a simple command
|
||||
with arguments separated by single spaces. If the program name
|
||||
contains a '/', the part after the last '/' is taken as ARGV[0]. If the
|
||||
with arguments separated by spaces. If the program name
|
||||
contains '/', only the part after the last '/' is taken as ARGV[0]. If the
|
||||
program name is a relative
|
||||
path, the code(execvp()) semantics for finding the program via
|
||||
code($PATH)
|
||||
apply. After successful program start, socat() writes data to stdin of the
|
||||
process and reads from its stdout using a unixdomain() socket generated by
|
||||
code(socketpair()) per default. (link(example)(EXAMPLE_ADDRESS_EXEC)) nl()
|
||||
code($PATH) apply. nl()
|
||||
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()
|
||||
Useful options:
|
||||
link(path)(OPTION_PATH),
|
||||
@ -296,11 +346,10 @@ label(ADDRESS_EXEC)dit(bf(tt(EXEC:<command-line>)))
|
||||
link(su)(OPTION_SUBSTUSER),
|
||||
link(su-d)(OPTION_SUBSTUSER_DELAYED),
|
||||
link(nofork)(OPTION_NOFORK),
|
||||
link(pty)(OPTION_PTY),
|
||||
link(commtype)(OPTION_COMMTYPE),
|
||||
link(stderr)(OPTION_STDERR),
|
||||
link(ctty)(OPTION_CTTY),
|
||||
link(setsid)(OPTION_SETSID),
|
||||
link(pipes)(OPTION_PIPES),
|
||||
link(login)(OPTION_LOGIN),
|
||||
link(sigint)(OPTION_SIGINT),
|
||||
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(UNIX-SENDTO)(ADDRESS_UNIX_SENDTO)
|
||||
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
|
||||
the network interface. Currently only available on Linux.
|
||||
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET) nl()
|
||||
Useful options:
|
||||
link(pf)(OPTION_PROTOCOL_FAMILY)
|
||||
link(pf)(OPTION_PROTOCOL_FAMILY)nl()
|
||||
link(type)(OPTION_SO_TYPE)nl()
|
||||
See also: link(ip-recv)(ADDRESS_IP_RECV)
|
||||
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
|
||||
4 or 6 is used. It receives packets from multiple unspecified peers and merges the data.
|
||||
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
|
||||
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()
|
||||
@ -534,13 +583,14 @@ label(ADDRESS_OPENSSL_LISTEN)dit(bf(tt(OPENSSL-LISTEN:<port>)))
|
||||
label(ADDRESS_NAMED_PIPE)dit(bf(tt(PIPE:<filename>)))
|
||||
If link(<filename>)(TYPE_FILENAME) already exists, it is opened.
|
||||
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()
|
||||
Note: When a pipe is used for both reading and writing, it works
|
||||
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
|
||||
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()
|
||||
Useful options:
|
||||
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
|
||||
echo, because everything written
|
||||
to it appeares immediately as read data.nl()
|
||||
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
|
||||
option code(-b 2048) nl()
|
||||
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
|
||||
option link(code(-b 2048))(option_b) nl()
|
||||
Option groups: link(FD)(GROUP_FD) nl()
|
||||
See also: link(named pipe)(ADDRESS_NAMED_PIPE)
|
||||
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
|
||||
link(pf)(OPTION_PROTOCOL_FAMILY), and sends a CONNECT
|
||||
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
|
||||
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()
|
||||
@ -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>)))
|
||||
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
|
||||
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).
|
||||
Note that opening
|
||||
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()
|
||||
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
|
||||
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)
|
||||
numbers. Consult your OS documentation and include files to find the
|
||||
appropriate values. The remote-address must be the link(data)(TYPE_DATA)
|
||||
representation of a sockaddr structure without sa_family and (BSD) sa_len
|
||||
components.nl()
|
||||
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()
|
||||
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY)nl()
|
||||
Useful options:
|
||||
@ -699,14 +749,14 @@ label(ADDRESS_SOCKET_CONNECT)dit(bf(tt(SOCKET-CONNECT:<domain>:<protocol>:<remot
|
||||
link(SOCKET-SENDTO)(ADDRESS_SOCKET_SENDTO)
|
||||
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
|
||||
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)
|
||||
numbers. Consult your OS documentation and include files to find the
|
||||
appropriate values. The remote-address must be the link(data)(TYPE_DATA)
|
||||
representation of a sockaddr structure without sa_family and (BSD) sa_len
|
||||
components.nl()
|
||||
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()
|
||||
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(RANGE)(GROUP_RANGE)nl()
|
||||
Useful options:
|
||||
@ -724,14 +774,14 @@ label(ADDRESS_SOCKET_DATAGRAM)dit(bf(tt(SOCKET-DATAGRAM:<domain>:<type>:<protoco
|
||||
link(SOCKET-RECVFROM)(ADDRESS_SOCKET_RECVFROM)
|
||||
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
|
||||
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
|
||||
link(int)(TYPE_INT) numbers. Consult your OS documentation and include files
|
||||
to find the appropriate values. The local-address must be the
|
||||
link(data)(TYPE_DATA) representation of a sockaddr structure without
|
||||
sa_family and (BSD) sa_len components.nl()
|
||||
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()
|
||||
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:
|
||||
@ -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_RECV)
|
||||
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
|
||||
parameters have to be specified by link(int)(TYPE_INT) numbers. Consult your
|
||||
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-RECVFROM)(ADDRESS_SOCKET_RECVFROM)
|
||||
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
|
||||
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
|
||||
@ -792,7 +842,7 @@ label(ADDRESS_SOCKET_RECVFROM)dit(bf(tt(SOCKET-RECVFROM:<domain>:<type>:<protoco
|
||||
link(SOCKET-RECV)(ADDRESS_SOCKET_RECV)
|
||||
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
|
||||
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)
|
||||
numbers. Consult your OS documentation and include files to find the
|
||||
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()
|
||||
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)
|
||||
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
|
||||
and invokes the specified program with code(system()). Please note that
|
||||
<shell-command> [link(string)(TYPE_STRING)] must
|
||||
not contain ',' or "!!", and that shell meta characters may have to be
|
||||
protected.
|
||||
not contain unprotected ',' or "%", and that shell meta characters may have
|
||||
to be escaped.
|
||||
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()
|
||||
Useful options:
|
||||
link(path)(OPTION_PATH),
|
||||
@ -870,11 +934,10 @@ label(ADDRESS_SYSTEM)dit(bf(tt(SYSTEM:<shell-command>)))
|
||||
link(su)(OPTION_SUBSTUSER),
|
||||
link(su-d)(OPTION_SUBSTUSER_DELAYED),
|
||||
link(nofork)(OPTION_NOFORK),
|
||||
link(pty)(OPTION_PTY),
|
||||
link(commtype)(OPTION_COMMTYPE),
|
||||
link(stderr)(OPTION_STDERR),
|
||||
link(ctty)(OPTION_CTTY),
|
||||
link(setsid)(OPTION_SETSID),
|
||||
link(pipes)(OPTION_PIPES),
|
||||
link(sigint)(OPTION_SIGINT),
|
||||
link(sigquit)(OPTION_SIGQUIT)nl()
|
||||
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>)))
|
||||
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
|
||||
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).
|
||||
Note that opening
|
||||
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>)))
|
||||
Creates a Linux TUN/TAP device and assignes to it the address and netmask
|
||||
defined by the parameters. The resulting network interface is ready for use
|
||||
by other processes; socat serves its "wire side". This address requires read
|
||||
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).
|
||||
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
|
||||
from that peer socket only.
|
||||
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()
|
||||
Useful options:
|
||||
link(ttl)(OPTION_TTL),
|
||||
@ -1104,7 +1167,7 @@ label(ADDRESS_UDP_RECVFROM)dit(bf(tt(UDP-RECVFROM:<port>)))
|
||||
option
|
||||
where each arriving packet - from arbitrary peers - is handled by its own sub
|
||||
process. This allows a behaviour similar to typical UDP based servers like ntpd
|
||||
or named. This address works well with socat SENDTO address peers.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()
|
||||
Useful options:
|
||||
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
|
||||
depending on option link(pf)(OPTION_PROTOCOL_FAMILY).
|
||||
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()
|
||||
Useful options:
|
||||
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
|
||||
fails (use option link(unlink-early)(OPTION_UNLINK_EARLY)!).
|
||||
Note that opening this address usually blocks until a client connects.
|
||||
Beginning with socat version 1.4.3, the file system entry is removed when
|
||||
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()
|
||||
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),
|
||||
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>)))
|
||||
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 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),
|
||||
link(NAMED)(GROUP_NAMED),link(UNIX)(GROUP_SOCK_UNIX)nl()
|
||||
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)].
|
||||
Receives one packet and may send one or more answer packets to that peer.
|
||||
This mode is particularly useful with fork option where each arriving packet - from arbitrary peers - is handled by its own sub process.
|
||||
This address works well with socat UNIX-SENDTO address peers.nl()
|
||||
This address works well with socat() UNIX-SENDTO address peers.nl()
|
||||
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),
|
||||
link(NAMED)(GROUP_NAMED),link(CHILD)(GROUP_CHILD),
|
||||
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>)))
|
||||
Creates a unixdomain() datagram socket [link(<filename>)(TYPE_FILENAME)].
|
||||
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.
|
||||
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),
|
||||
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
|
||||
with em(notice) level instead of em(error).
|
||||
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()
|
||||
This option is experimental.
|
||||
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.
|
||||
tt(close(2)) "unlinks" the socket from the process but keeps it active as
|
||||
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
|
||||
the file descriptors.
|
||||
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.
|
||||
For EXEC and SYSTEM addresses and for LISTEN and CONNECT type addresses with
|
||||
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()
|
||||
label(OPTION_CHROOT)dit(bf(tt(chroot=<directory>)))
|
||||
Performs a code(chroot()) operation to link(<directory>)(TYPE_DIRECTORY)
|
||||
@ -1701,9 +1764,9 @@ startdit()
|
||||
label(OPTION_HISTORY)dit(bf(tt(history=<filename>)))
|
||||
Reads and writes history from/to link(<filename>)(TYPE_FILENAME) (link(example)(EXAMPLE_OPTION_HISTORY)).
|
||||
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
|
||||
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
|
||||
of the terminal.
|
||||
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
|
||||
after the lastest newline character and before an input character was
|
||||
typed. The pattern is a regular expression, e.g.
|
||||
"^[Pp]assword:.*$" or "([Uu]ser:|[Pp]assword:)". See regex(7) for details.
|
||||
"^[Pp]assword:.*$" or "([Uu]ser:|[Pp]assword:)". See regex\(7) for details.
|
||||
(link(example)(EXAMPLE_OPTION_NOECHO))
|
||||
label(OPTION_PROMPT)dit(bf(tt(prompt=<string>)))
|
||||
Passes the string as prompt to the readline function. readline prints this
|
||||
prompt when stepping through the history. If this string matches a constant
|
||||
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.
|
||||
enddit()
|
||||
|
||||
@ -1737,7 +1800,7 @@ label(OPTION_CR)dit(bf(tt(cr)))
|
||||
label(OPTION_CRNL)dit(bf(tt(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)).
|
||||
Note: socat simply strips all CR characters.
|
||||
Note: socat() simply strips all CR characters.
|
||||
label(OPTION_IGNOREEOF)dit(bf(tt(ignoreeof)))
|
||||
When EOF occurs on this channel, socat() ignores it and tries to read more
|
||||
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
|
||||
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
|
||||
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>)))
|
||||
Like tt(setsockopt-int), but <optval> must be provided in
|
||||
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_DNSRCH)dit(bf(tt(res-dnsrch)))
|
||||
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
|
||||
address they are applied to.
|
||||
|
||||
@ -2026,7 +2089,7 @@ startdit()enddit()nl()
|
||||
|
||||
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
|
||||
sockets.
|
||||
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
|
||||
(HP-UX).
|
||||
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).
|
||||
label(OPTION_TCP_PAWS)dit(bf(tt(paws)))
|
||||
Enables the "protect against wrapped sequence numbers" feature (Tru64).
|
||||
@ -2158,7 +2221,7 @@ startdit()
|
||||
label(OPTION_SOURCEPORT)dit(bf(tt(sourceport=<port>)))
|
||||
For outgoing (client) TCP and UDP connections, it sets the source
|
||||
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)).
|
||||
label(OPTION_LOWPORT)dit(bf(tt(lowport)))
|
||||
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).
|
||||
label(OPTION_IGNORECR)dit(bf(tt(ignorecr)))
|
||||
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.
|
||||
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.
|
||||
server violates this standard, socat() might not understand its answer.
|
||||
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.
|
||||
label(OPTION_PROXY_AUTHORIZATION)dit(bf(tt(proxyauth=<username>:<password>)))
|
||||
Provide "basic" authentication to the proxy server. The argument to the
|
||||
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
|
||||
server unencrypted (base64 encoded) and might be sniffed.
|
||||
label(OPTION_PROXY_RESOLVE)dit(bf(tt(resolve)))
|
||||
Per default, socat sends to the proxy a CONNECT request containing the
|
||||
target hostname. With this option, socat resolves the hostname locally and
|
||||
Per default, socat() sends to the proxy a CONNECT request containing the
|
||||
target hostname. With this option, socat() resolves the hostname locally and
|
||||
sends the IP address. Please note that, according to RFC 2396, only name
|
||||
resolution to IPv4 addresses is implemented.
|
||||
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
|
||||
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
|
||||
socat process.
|
||||
socat() process.
|
||||
startdit()
|
||||
label(OPTION_NOFORK)dit(bf(tt(nofork)))
|
||||
Does not fork a subprocess for executing the program, instead calls execvp()
|
||||
or system() directly from the actual socat instance. This avoids the
|
||||
Does not fork a subprocess for executing the program, instead calls execvp\()
|
||||
or system\() directly from the actual socat() instance. This avoids the
|
||||
overhead of another process between the program and its peer,
|
||||
but introduces a lot of restrictions:
|
||||
startit()
|
||||
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() the first socat address cannot be OPENSSL or READLINE
|
||||
it() socat options -b, -t, -D, -l, -v, -x become useless
|
||||
it() the first socat() address cannot be OPENSSL or READLINE
|
||||
it() socat() options -b, -t, -D, -l, -v, -x become useless
|
||||
it() for both addresses, options ignoreeof, cr, and crnl become useless
|
||||
it() for the second address (the one with option nofork), options
|
||||
append, metaCOMMENT(async,) cloexec, flock, user, group, mode, nonblock,
|
||||
perm-late, setlk, and setpgid cannot be applied. Some of these could be
|
||||
used on the first address though.
|
||||
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)))
|
||||
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)))
|
||||
Establishes communication with the sub process using a pseudo terminal
|
||||
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
|
||||
instead of a socket pair. Creates the pty with an available mechanism. If
|
||||
openpty and ptmx are both available, it uses ptmx because this is POSIX
|
||||
compliant (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)))
|
||||
Makes the pty the controlling tty of the sub process (link(example)(EXAMPLE_OPTION_CTTY)).
|
||||
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)).
|
||||
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.
|
||||
If no address has this option, socat terminates on these signals.
|
||||
If no address has this option, socat() terminates on these signals.
|
||||
enddit()
|
||||
|
||||
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)).
|
||||
label(OPTION_PTY_WAIT_SLAVE)dit(bf(tt(wait-slave)))
|
||||
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,
|
||||
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.
|
||||
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
|
||||
@ -2629,14 +2697,14 @@ label(OPTION_OPENSSL_PSEUDO)dit(bf(tt(pseudo)))
|
||||
gathering daemon can be utilized, this option activates a mechanism for
|
||||
providing pseudo entropy. This is archieved by taking the current time in
|
||||
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!
|
||||
label(OPTION_OPENSSL_FIPS)dit(bf(tt(fips)))
|
||||
Enables FIPS mode if compiled in. For info about the FIPS encryption
|
||||
implementation standard see lurl(http://oss-institute.org/fips-faq.html).
|
||||
This mode might require that the involved certificates are generated with a
|
||||
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()
|
||||
|
||||
startdit()enddit()nl()
|
||||
@ -2667,7 +2735,7 @@ Options that control Linux TUN/TAP interface device addresses.
|
||||
|
||||
startdit()
|
||||
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).
|
||||
label(OPTION_TUN_NAME)dit(bf(tt(tun-name=<if-name>)))
|
||||
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)
|
||||
A string specifying a program name and its arguments, separated by single
|
||||
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)
|
||||
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
|
||||
@ -2801,7 +2883,7 @@ label(TYPE_SOCKNAME)dit(sockname)
|
||||
A socket address. See address-option link(`bind')(OPTION_BIND)
|
||||
label(TYPE_STRING)dit(string)
|
||||
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.
|
||||
label(TYPE_TCP_SERVICE)dit(TCP service)
|
||||
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
|
||||
allows immediate restart after master process's termination, even if some child
|
||||
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
|
||||
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
|
||||
ttyS0's terminal parameters to practicable values, link(crnl)(OPTION_CRNL)
|
||||
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.
|
||||
|
||||
|
||||
@ -3044,7 +3126,7 @@ htmlcommand(<dt><code><strong>socat -u TCP4-LISTEN:3334,reuseaddr,fork \</strong
|
||||
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)).
|
||||
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
|
||||
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).
|
||||
An application that expects a serial line or modem
|
||||
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).
|
||||
|
||||
|
||||
@ -3121,7 +3203,7 @@ Otherwise the connection is terminated.
|
||||
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
|
||||
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)
|
||||
@ -3133,7 +3215,7 @@ verified against cafile.crt.nl()
|
||||
The second address ('PIPE') can be replaced by almost any other socat
|
||||
address.nl()
|
||||
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)))
|
||||
@ -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
|
||||
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
|
||||
connection to 9999 (close(2) just unlinks the inode which stays active as long
|
||||
as the parent process lives; shutdown(2) would actively terminate the
|
||||
connection to 9999 (close\(2) just unlinks the inode which stays active as long
|
||||
as the parent process lives; shutdown\(2) would actively terminate the
|
||||
connection).
|
||||
|
||||
|
||||
@ -3195,7 +3277,7 @@ tt(SO_BROADCAST).
|
||||
label(EXAMPLE_ADDRESS_IP4_BROADCAST_CLIENT)
|
||||
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.
|
||||
|
||||
|
||||
@ -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
|
||||
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
|
||||
both devices. Use pppd on device tt(/var/run/ppp) then.
|
||||
|
||||
@ -3243,7 +3325,7 @@ servers), and the original client request.
|
||||
|
||||
|
||||
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
|
||||
variables provided by socat. On BSD based systems you have to replace
|
||||
@ -3308,7 +3390,7 @@ label(ENVIRONMENT_VARIABLES)
|
||||
manpagesection(ENVIRONMENT VARIABLES)
|
||||
|
||||
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
|
||||
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
|
||||
be used for listen, recv, and recvfrom addresses if no
|
||||
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
|
||||
version to
|
||||
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 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.
|
||||
|
||||
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_MAIN_WAIT) (input)) Specifies the time (seconds) to sleep the
|
||||
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
|
||||
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
|
||||
id. Forking for link(exec)(ADDRESS_EXEC) and link(system)(ADDRESS_SYSTEM) does
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
dit(bf(SOCAT_IP_DSTADDR) (output)) With all IPv4 based RECVFROM addresses where
|
||||
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
|
||||
particularly useful to identify broadcast and multicast addressed packets.
|
||||
|
||||
dit(bf(SOCAT_IP_IF) (output)) With all IPv4 based RECVFROM addresses where
|
||||
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.
|
||||
|
||||
dit(bf(SOCAT_IP_LOCADDR) (output)) With all IPv4 based RECVFROM
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
dit(bf(SOCAT_IPV6_HOPLIMIT) (output)) With all IPv6 based RECVFROM addresses
|
||||
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
|
||||
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.
|
||||
|
||||
dit(bf(SOCAT_IPV6_TCLASS) (output)) With all IPv6 based RECVFROM addresses
|
||||
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
|
||||
link(-lh)(option_lh)).
|
||||
@ -3455,13 +3540,13 @@ standard specifications available on the Internet for free.
|
||||
label(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)
|
||||
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.
|
||||
|
||||
Address option ftruncate without value uses default 1 instead of 0.
|
||||
@ -3479,8 +3564,8 @@ label(SEEALSO)
|
||||
manpageseealso()
|
||||
|
||||
COMMENT(procan\(1), filan\(1), )
|
||||
nc(1), netcat6(1), sock(1), rinetd(8), cage(1), socks.conf(5), openssl(1),
|
||||
stunnel(8), pty(1), rlwrap(1), setsid(1)
|
||||
nc\(1), netcat6\(1), sock\(1), rinetd\(8), cage\(1), socks.conf\(5),
|
||||
openssl\(1), stunnel\(8), pty\(1), rlwrap\(1), setsid\(1)
|
||||
|
||||
Socat() home page lurl(http://www.dest-unreach.org/socat/)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#! /bin/bash
|
||||
# source: proxyecho.sh
|
||||
# Copyright Gerhard Rieger 2003
|
||||
# Copyright Gerhard Rieger 2003-2009
|
||||
# Published under the GNU General Public License V.2, see file COPYING
|
||||
|
||||
# perform primitive simulation of a proxy server with echo function via stdio.
|
||||
@ -56,4 +56,4 @@ echo "HTTP/1.0${SPACES}200 OK"
|
||||
echo
|
||||
|
||||
# perform echo function
|
||||
$CAT
|
||||
exec $CAT
|
||||
|
21
socat.c
21
socat.c
@ -1,9 +1,9 @@
|
||||
/* 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 */
|
||||
|
||||
/* this is the main source, including command line option parsing, general
|
||||
control, and the data shuffler */
|
||||
/* this is the main source, including command line option parsing and general
|
||||
control */
|
||||
|
||||
#include "config.h"
|
||||
#include "xioconfig.h" /* what features are enabled */
|
||||
@ -220,6 +220,21 @@ int main(int argc, const char *argv[]) {
|
||||
xioopts.preferred_ip = arg1[0][1];
|
||||
break;
|
||||
#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 '-': /*! this is hardcoded "--" */
|
||||
case ',':
|
||||
|
4
sycls.c
4
sycls.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* we only show the first word of the fd_set's; hope this is enough for most
|
||||
cases. */
|
||||
int Pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
@ -776,6 +777,7 @@ int Pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
errno = _errno;
|
||||
return result;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
pid_t Fork(void) {
|
||||
pid_t pid;
|
||||
|
334
test.sh
334
test.sh
@ -1,6 +1,6 @@
|
||||
#! /bin/bash
|
||||
# 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
|
||||
|
||||
# perform lots of tests on socat
|
||||
@ -2215,70 +2215,38 @@ esac
|
||||
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
|
||||
*%functions%*|*%exec%*|*%$NAME%*)
|
||||
TEST="$NAME: simple echo via exec of cat with socketpair"
|
||||
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"
|
||||
*%functions%*|*%$commtype%*|*%$exec%*|*%$NAME%*)
|
||||
TEST="$NAME: simple echo via $exec() of cat using $commtype"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! testaddrs pty >/dev/null; then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N
|
||||
elif [ "$feature" != . ] && ! testaddrs $feature >/dev/null; then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}$commtype not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
else
|
||||
testecho "$N" "$TEST" "" "exec:$CAT,pty,$PTYOPTS" "$opts"
|
||||
testecho "$N" "$TEST" "" "$exec:$CAT,commtype=$commtype,$addropts" "$opts" "$val_t"
|
||||
fi
|
||||
esac
|
||||
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
|
||||
@ -3751,7 +3719,8 @@ NAME=CHAINUNIDIR
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%$NAME%*)
|
||||
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
|
||||
N=$((N+1))
|
||||
|
||||
@ -3759,7 +3728,7 @@ NAME=CHAINREVDIR
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%$NAME%*)
|
||||
TEST="$NAME: two unidirectional chains, right to left"
|
||||
testchain "$N" "$TEST" "^test|stdout" "^test|stdin" "-U $opts" "><"
|
||||
testchain "$N" "$TEST" "^test|stdout" "^test|stdin" "-U $opts" "><" "$val_t"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
@ -3806,7 +3775,7 @@ N=$((N+1))
|
||||
|
||||
NAME=OPENSSL_TCP4
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
|
||||
*%functions%*|*%chain%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
|
||||
TEST="$NAME: openssl connect"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! testaddrs openssl >/dev/null; then
|
||||
@ -3859,7 +3828,7 @@ N=$((N+1))
|
||||
|
||||
NAME=OPENSSLLISTEN_TCP4
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
|
||||
*%functions%*|*%chain%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
|
||||
TEST="$NAME: openssl listen"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! testaddrs openssl >/dev/null; then
|
||||
@ -4136,7 +4105,7 @@ N=$((N+1))
|
||||
|
||||
NAME=SOCKS4CONNECT_TCP4
|
||||
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"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! testaddrs socks4 >/dev/null; then
|
||||
@ -4226,7 +4195,7 @@ N=$((N+1))
|
||||
|
||||
NAME=SOCKS4ACONNECT_TCP4
|
||||
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"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! testaddrs socks4a >/dev/null; then
|
||||
@ -4316,7 +4285,7 @@ N=$((N+1))
|
||||
|
||||
NAME=PROXYCONNECT_TCP4
|
||||
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"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! testaddrs proxy >/dev/null; then
|
||||
@ -4592,7 +4561,7 @@ N=$((N+1))
|
||||
|
||||
NAME=PROXY2SPACES
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%proxy%*|*%$NAME%*)
|
||||
*%functions%*|*%chain%*|*%proxy%*|*%$NAME%*)
|
||||
TEST="$NAME: proxy connect accepts status with multiple spaces"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! testaddrs proxy >/dev/null; then
|
||||
@ -4888,7 +4857,7 @@ N=$((N+1))
|
||||
#!
|
||||
NAME=OUTBOUNDIN
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%proxy%*|*%$NAME%*)
|
||||
*%functions%*|*%chain%*|*%proxy%*|*%$NAME%*)
|
||||
TEST="$NAME: gender changer via SSL through HTTP proxy, oneshot"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! feat=$(testaddrs openssl proxy); then
|
||||
@ -4975,7 +4944,7 @@ PORT=$((RANDOM+16184))
|
||||
#!
|
||||
NAME=INTRANETRIPPER
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%proxy%*|*%$NAME%*)
|
||||
*%functions%*|*%chain%*|*%proxy%*|*%$NAME%*)
|
||||
TEST="$NAME: gender changer via SSL through HTTP proxy, daemons"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! feat=$(testaddrs openssl proxy); then
|
||||
@ -5940,7 +5909,7 @@ N=$((N+1))
|
||||
|
||||
NAME=OPENSSLLISTENDSA
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%$NAME%*)
|
||||
*%functions%*|*%chain%*|*%openssl%*|*%tcp%*|*%$NAME%*)
|
||||
TEST="$NAME: openssl listen with DSA certificate"
|
||||
if ! eval $NUMCOND; 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
|
||||
# socket.
|
||||
# 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
|
||||
# at the target service.
|
||||
if ! eval $NUMCOND; then :; else
|
||||
@ -10114,13 +10083,14 @@ printf "test $F_n $TEST... " $N
|
||||
$CMD1 >"$tf" 2>"${te}1" &
|
||||
pid=$! # background process id
|
||||
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"
|
||||
if [ $? -ne 0 ]; then
|
||||
$PRINTF "$FAILED: $SOCAT:\n"
|
||||
echo "$CMD1 &"
|
||||
cat "${te}1"
|
||||
echo "$CMD2"
|
||||
cat "$te"
|
||||
cat "${te}2"
|
||||
numFAIL=$((numFAIL+1))
|
||||
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
|
||||
$PRINTF "$FAILED: diff:\n"
|
||||
@ -10147,7 +10117,7 @@ pf="$(echo $PF |tr A-Z a-z)"
|
||||
proto="$(echo $KEYW |tr A-Z a-z)"
|
||||
NAME=OPENSSL_${KEYW}_FORK
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%openssl%*|*%sctp%*|*%$pf%*|*%$NAME%*)
|
||||
*%functions%*|*%chain%*|*%openssl%*|*%sctp%*|*%$pf%*|*%$NAME%*)
|
||||
TEST="$NAME: openssl over SCTP with server fork"
|
||||
if ! eval $NUMCOND; 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"
|
||||
|
||||
if [ "$numFAIL" -gt 0 ]; then
|
||||
|
27
xio-creat.c
27
xio-creat.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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];
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
int fd;
|
||||
bool exists;
|
||||
bool opt_unlink_close = false;
|
||||
int result;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
retropt_bool(opts, OPT_UNLINK_CLOSE, &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);
|
||||
}
|
||||
fd->stream.opt_unlink_close = true;
|
||||
xfd->stream.opt_unlink_close = true;
|
||||
}
|
||||
|
||||
Notice2("creating regular file \"%s\" for %s", filename, ddirection[rw]);
|
||||
if ((result = _xioopen_creat(filename, rw, opts)) < 0)
|
||||
return result;
|
||||
fd->stream.fd1 = fd->stream.fd2 = result;
|
||||
fd->stream.fdtype = FDTYPE_SINGLE;
|
||||
if ((fd = _xioopen_creat(filename, rw, opts)) < 0)
|
||||
return fd;
|
||||
if (XIOWITHRD(rw)) xfd->stream.rfd = fd;
|
||||
if (XIOWITHWR(rw)) xfd->stream.wfd = fd;
|
||||
|
||||
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;
|
||||
|
||||
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 0;
|
||||
|
38
xio-exec.c
38
xio-exec.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* this file contains the source for opening addresses of exec type */
|
||||
@ -16,29 +16,49 @@
|
||||
|
||||
#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. */
|
||||
xiofile_t *fd,
|
||||
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[] = {
|
||||
(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 };
|
||||
|
||||
|
||||
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. */
|
||||
xiofile_t *fd,
|
||||
unsigned groups,
|
||||
int dummy1, int dummy2, int dummy3
|
||||
int inter, int form, int dummy3
|
||||
) {
|
||||
int status;
|
||||
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);
|
||||
|
||||
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) { /* child */
|
||||
const char *ends[] = { " ", NULL };
|
||||
|
@ -1,11 +1,12 @@
|
||||
/* 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 */
|
||||
|
||||
#ifndef __xio_exec_h_included
|
||||
#define __xio_exec_h_included 1
|
||||
|
||||
extern const union xioaddr_desc *xioaddrs_exec[];
|
||||
extern const union xioaddr_desc *xioaddrs_exec1[];
|
||||
|
||||
extern const struct optdesc opt_dash;
|
||||
|
||||
|
8
xio-fd.c
8
xio-fd.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* this file contains common file descriptor related option definitions */
|
||||
@ -74,8 +74,10 @@ const struct optdesc opt_flock_ex_nb = { "flock-ex-nb", "flock-nb", OPT_FLOCK_E
|
||||
const struct optdesc opt_cool_write = { "cool-write", "coolwrite", OPT_COOL_WRITE, GROUP_FD, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.cool_write };
|
||||
|
||||
/* control closing of connections */
|
||||
const struct optdesc opt_end_close = { "end-close", "close", OPT_END_CLOSE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.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_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_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 ******/
|
||||
const struct optdesc opt_ioctl_void = { "ioctl-void", "ioctl", OPT_IOCTL_VOID, GROUP_FD, PH_FD, TYPE_INT, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
|
||||
|
2
xio-fd.h
2
xio-fd.h
@ -43,6 +43,8 @@ extern const struct optdesc opt_f_setlkw_wr;
|
||||
extern const struct optdesc opt_cool_write;
|
||||
extern const struct optdesc opt_end_close;
|
||||
extern const struct optdesc opt_shut_none;
|
||||
extern const struct optdesc opt_shut_down;
|
||||
extern const struct optdesc opt_shut_close;
|
||||
extern const struct optdesc opt_streams_i_push;
|
||||
|
||||
#endif /* !defined(__xio_fd_h_included) */
|
||||
|
62
xio-fdnum.c
62
xio-fdnum.c
@ -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);
|
||||
|
||||
|
||||
const struct xioaddr_endpoint_desc xioaddr_fdnum1 = { XIOADDR_ENDPOINT, "fd", 1, XIOBIT_ALL, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_fdnum, 0, 0, 0 HELP(":<num>") };
|
||||
const struct xioaddr_endpoint_desc xioaddr_fdnum2 = { XIOADDR_ENDPOINT, "fd", 2, XIOBIT_RDWR, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_fdnum, 0, 0, 0 HELP(":<numout>:<numin>") };
|
||||
const 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_UNSPEC, XIOCLOSE_CLOSE, xioopen_fdnum, 0, 0, 0 HELP(":<numout>:<numin>") };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_fdnum[] = {
|
||||
(union xioaddr_desc *)&xioaddr_fdnum1,
|
||||
@ -30,6 +30,7 @@ static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts,
|
||||
char *a1;
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
int numfd1, numfd2 = -1;
|
||||
int numrfd, numwfd;
|
||||
int result;
|
||||
|
||||
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) {
|
||||
Warn("two file descriptors given for unidirectional transfer");
|
||||
}
|
||||
numfd2 = numfd1;
|
||||
numfd1 = strtoul(argv[2], &a1, 0);
|
||||
numwfd = numfd1;
|
||||
numrfd = strtoul(argv[2], &a1, 0);
|
||||
if (*a1 != '\0') {
|
||||
Error1("error in FD number \"%s\"", argv[2]);
|
||||
}
|
||||
/* we dont want to see these fds in child processes */
|
||||
if (Fcntl_l(numfd2, F_SETFD, FD_CLOEXEC) < 0) {
|
||||
Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", numfd2, strerror(errno));
|
||||
if (Fcntl_l(numrfd, F_SETFD, FD_CLOEXEC) < 0) {
|
||||
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) {
|
||||
Notice2("using file descriptor %d for %s", numfd1, ddirection[rw]);
|
||||
Notice2("using file descriptor %d for %s",
|
||||
numrfd>=0?numrfd:numwfd, ddirection[rw]);
|
||||
} else {
|
||||
Notice4("using file descriptors %d for %s and %d for %s", numfd1, ddirection[((rw+1)&1)-1], numfd2, ddirection[((rw+1)&2)-1]);
|
||||
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 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.
|
||||
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;
|
||||
xfd->stream.fd2 = numfd2;
|
||||
if (numfd2 >= 0) {
|
||||
xfd->stream.fdtype = FDTYPE_DOUBLE;
|
||||
if (numwfd >= 0) {
|
||||
if (Fstat(numwfd, &buf) < 0) {
|
||||
Warn2("fstat(%d, ): %s", numwfd, strerror(errno));
|
||||
}
|
||||
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 {
|
||||
xfd->stream.fdtype = FDTYPE_SINGLE;
|
||||
fd = numwfd;
|
||||
}
|
||||
|
||||
#if WITH_TERMIOS
|
||||
if (Isatty(xfd->stream.fd1)) {
|
||||
if (Tcgetattr(xfd->stream.fd1, &xfd->stream.savetty) < 0) {
|
||||
if (Isatty(fd)) {
|
||||
if (Tcgetattr(fd, &xfd->stream.savetty) < 0) {
|
||||
Warn2("cannot query current terminal settings on fd %d: %s",
|
||||
xfd->stream.fd1, strerror(errno));
|
||||
fd, strerror(errno));
|
||||
} else {
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
33
xio-file.c
33
xio-file.c
@ -76,51 +76,52 @@ const union xioaddr_desc *xioaddrs_open[] = {
|
||||
if the filesystem entry already exists, the data is appended
|
||||
if it does not exist, a file is created and the data is appended
|
||||
*/
|
||||
static int xioopen_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];
|
||||
int rw = (xioflags & XIO_ACCMODE);
|
||||
int fd;
|
||||
bool exists;
|
||||
bool opt_unlink_close = false;
|
||||
int result;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
retropt_bool(opts, OPT_UNLINK_CLOSE, &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);
|
||||
}
|
||||
fd->stream.opt_unlink_close = true;
|
||||
xfd->stream.opt_unlink_close = true;
|
||||
}
|
||||
|
||||
Notice3("opening %s \"%s\" for %s",
|
||||
filetypenames[(result&S_IFMT)>>12], filename, ddirection[rw]);
|
||||
if ((result = _xioopen_open(filename, rw, opts)) < 0)
|
||||
return result;
|
||||
fd->stream.fd1 = result;
|
||||
fd->stream.fdtype = FDTYPE_SINGLE;
|
||||
if ((fd = _xioopen_open(filename, rw, opts)) < 0)
|
||||
return fd;
|
||||
if (XIOWITHRD(rw)) xfd->stream.rfd = fd;
|
||||
if (XIOWITHWR(rw)) xfd->stream.wfd = fd;
|
||||
|
||||
#if WITH_TERMIOS
|
||||
if (Isatty(fd->stream.fd1)) {
|
||||
if (Tcgetattr(fd->stream.fd1, &fd->stream.savetty) < 0) {
|
||||
if (Isatty(fd)) {
|
||||
if (Tcgetattr(fd, &xfd->stream.savetty) < 0) {
|
||||
Warn2("cannot query current terminal settings on fd %d: %s",
|
||||
fd->stream.fd1, strerror(errno));
|
||||
fd, strerror(errno));
|
||||
} else {
|
||||
fd->stream.ttyvalid = true;
|
||||
xfd->stream.ttyvalid = true;
|
||||
}
|
||||
}
|
||||
#endif /* WITH_TERMIOS */
|
||||
|
||||
applyopts_named(filename, opts, PH_FD);
|
||||
applyopts(fd->stream.fd1, opts, PH_FD);
|
||||
applyopts_cloexec(fd->stream.fd1, opts);
|
||||
applyopts(fd, opts, PH_FD);
|
||||
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 0;
|
||||
|
60
xio-gopen.c
60
xio-gopen.c
@ -14,7 +14,7 @@
|
||||
|
||||
#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>") };
|
||||
@ -24,8 +24,10 @@ const union xioaddr_desc *xioaddrs_gopen[] = {
|
||||
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];
|
||||
int fd;
|
||||
int rw = (xioflags & XIO_ACCMODE);
|
||||
flags_t openflags = (xioflags & XIO_ACCMODE);
|
||||
mode_t st_mode;
|
||||
bool exists;
|
||||
@ -33,7 +35,7 @@ static int xioopen_gopen1(int argc, const char *argv[], struct opt *opts, int xi
|
||||
int 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;
|
||||
}
|
||||
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);
|
||||
|
||||
fd->stream.howtoshut = XIOSHUT_DOWN;
|
||||
fd->stream.howtoclose = XIOCLOSE_CLOSE;
|
||||
xfd->stream.howtoshut = XIOSHUT_DOWN;
|
||||
xfd->stream.howtoclose = XIOCLOSE_CLOSE;
|
||||
result =
|
||||
_xioopen_unix_client(&fd->stream, xioflags, groups, 0, opts, filename);
|
||||
_xioopen_unix_client(&xfd->stream, xioflags, groups, 0, opts, filename);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
if (xfd->stream.rfd >= 0) {
|
||||
fd = xfd->stream.rfd;
|
||||
} else {
|
||||
fd = xfd->stream.wfd;
|
||||
}
|
||||
|
||||
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",
|
||||
fd->stream.fd1, &us, uslen, strerror(errno));
|
||||
fd, &us, uslen, strerror(errno));
|
||||
} else {
|
||||
Notice1("successfully connected via %s",
|
||||
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);
|
||||
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);
|
||||
}
|
||||
fd->stream.opt_unlink_close = true;
|
||||
xfd->stream.opt_unlink_close = true;
|
||||
}
|
||||
if (fd->stream.howtoshut == XIOSHUT_UNSPEC)
|
||||
fd->stream.howtoshut = XIOSHUT_NONE;
|
||||
if (fd->stream.howtoclose == XIOCLOSE_UNSPEC)
|
||||
fd->stream.howtoclose = XIOCLOSE_CLOSE;
|
||||
if (xfd->stream.howtoshut == XIOSHUT_UNSPEC)
|
||||
xfd->stream.howtoshut = XIOSHUT_NONE;
|
||||
if (xfd->stream.howtoclose == XIOCLOSE_UNSPEC)
|
||||
xfd->stream.howtoclose = XIOCLOSE_CLOSE;
|
||||
|
||||
Notice3("opening %s \"%s\" for %s",
|
||||
filetypenames[(st_mode&S_IFMT)>>12], filename, ddirection[(xioflags&XIO_ACCMODE)]);
|
||||
if ((result = _xioopen_open(filename, openflags, opts)) < 0)
|
||||
return result;
|
||||
if ((fd = _xioopen_open(filename, openflags, opts)) < 0)
|
||||
return fd;
|
||||
#ifdef I_PUSH
|
||||
if (S_ISCHR(st_mode)) {
|
||||
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");
|
||||
}
|
||||
#endif
|
||||
fd->stream.fd1 = result;
|
||||
|
||||
#if WITH_TERMIOS
|
||||
if (Isatty(fd->stream.fd1)) {
|
||||
if (Tcgetattr(fd->stream.fd1, &fd->stream.savetty) < 0) {
|
||||
if (Isatty(fd)) {
|
||||
if (Tcgetattr(fd, &xfd->stream.savetty) < 0) {
|
||||
Warn2("cannot query current terminal settings on fd %d: %s",
|
||||
fd->stream.fd1, strerror(errno));
|
||||
fd, strerror(errno));
|
||||
} else {
|
||||
fd->stream.ttyvalid = true;
|
||||
xfd->stream.ttyvalid = true;
|
||||
}
|
||||
}
|
||||
#endif /* WITH_TERMIOS */
|
||||
applyopts_named(filename, opts, PH_FD);
|
||||
applyopts(fd->stream.fd1, opts, PH_FD);
|
||||
applyopts_cloexec(fd->stream.fd1, opts);
|
||||
applyopts(fd, opts, PH_FD);
|
||||
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;
|
||||
|
||||
if ((result = _xio_openlate(&fd->stream, opts)) < 0)
|
||||
if ((result = _xio_openlate(&xfd->stream, opts)) < 0)
|
||||
return result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ int _xioopen_interface(const char *ifname,
|
||||
struct opt *opts, int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups) {
|
||||
xiosingle_t *xfd = &xxfd->stream;
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
int pf = PF_PACKET;
|
||||
union sockaddr_union us = {{0}};
|
||||
socklen_t uslen;
|
||||
@ -38,6 +39,7 @@ int _xioopen_interface(const char *ifname,
|
||||
bool needbind = false;
|
||||
char *bindstring = NULL;
|
||||
struct sockaddr_ll sall = { 0 };
|
||||
int result;
|
||||
|
||||
if (ifindex(ifname, &ifidx, -1) < 0) {
|
||||
Error1("unknown interface \"%s\"", ifname);
|
||||
@ -70,9 +72,15 @@ int _xioopen_interface(const char *ifname,
|
||||
needbind = true;
|
||||
xfd->peersa = (union sockaddr_union)us;
|
||||
|
||||
return
|
||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||
opts, xioflags, xfd, groups, pf, socktype, 0);
|
||||
if ((result =
|
||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||
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
|
||||
|
@ -26,6 +26,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
||||
unsigned groups, int socktype, int ipproto,
|
||||
int pf) {
|
||||
struct single *xfd = &xxfd->stream;
|
||||
int rw = (xioflags & XIO_ACCMODE);
|
||||
struct opt *opts0 = NULL;
|
||||
const char *hostname = argv[1], *portname = argv[2];
|
||||
bool dofork = false;
|
||||
@ -98,6 +99,8 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
|
||||
if (!XIOWITHRD(rw)) xfd->rfd = -1;
|
||||
|
||||
#if WITH_RETRY
|
||||
if (dofork) {
|
||||
@ -121,7 +124,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
||||
|
||||
/* parent process */
|
||||
Notice1("forked off child process "F_pid, pid);
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->rfd);
|
||||
|
||||
/* with and without retry */
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
|
62
xio-listen.c
62
xio-listen.c
@ -110,6 +110,7 @@ int
|
||||
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 sockaddr sa;
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
socklen_t salen;
|
||||
int backlog = 5; /* why? 1 seems to cause problems under some load */
|
||||
char *rangename;
|
||||
@ -140,22 +141,21 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
|
||||
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;
|
||||
}
|
||||
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->fd1, opts, PH_BIND);
|
||||
if (Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1,
|
||||
applyopts(xfd->rfd, opts, PH_PREBIND);
|
||||
applyopts(xfd->rfd, opts, PH_BIND);
|
||||
if (Bind(xfd->rfd, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->rfd,
|
||||
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
|
||||
strerror(errno));
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->rfd);
|
||||
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
|
||||
fields that we want to know. */
|
||||
salen = sizeof(sa);
|
||||
if (Getsockname(xfd->fd1, us, &uslen) < 0) {
|
||||
if (Getsockname(xfd->rfd, us, &uslen) < 0) {
|
||||
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 (us->sa_family == AF_UNIX) {
|
||||
/*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 */
|
||||
|
||||
retropt_int(opts, OPT_BACKLOG, &backlog);
|
||||
if (Listen(xfd->fd1, backlog) < 0) {
|
||||
Error3("listen(%d, %d): %s", xfd->fd1, backlog, strerror(errno));
|
||||
if (Listen(xfd->rfd, backlog) < 0) {
|
||||
Error3("listen(%d, %d): %s", xfd->rfd, backlog, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
@ -211,8 +211,8 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
|
||||
#endif /* WITH_TCP || WITH_UDP */
|
||||
|
||||
retropt_int(opts, OPT_BACKLOG, &backlog);
|
||||
if (Listen(xfd->fd1, backlog) < 0) {
|
||||
Error3("listen(%d, %d): %s", xfd->fd1, backlog, strerror(errno));
|
||||
if (Listen(xfd->rfd, backlog) < 0) {
|
||||
Error3("listen(%d, %d): %s", xfd->rfd, backlog, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
@ -231,7 +231,7 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
|
||||
do {
|
||||
/*? int level = E_ERROR;*/
|
||||
Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname)));
|
||||
ps = Accept(xfd->fd1, (struct sockaddr *)&sa, &salen);
|
||||
ps = Accept(xfd->rfd, (struct sockaddr *)&sa, &salen);
|
||||
if (ps >= 0) {
|
||||
/*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", xfd->fd1, &sa, salen, ps);*/
|
||||
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) {
|
||||
Notice4("accept(%d, %p, {"F_Zu"}): %s",
|
||||
xfd->fd1, &sa, salen, strerror(errno));
|
||||
xfd->rfd, &sa, salen, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
Msg4(level, "accept(%d, %p, {"F_Zu"}): %s",
|
||||
xfd->fd1, &sa, salen, strerror(errno));
|
||||
Close(xfd->fd1);
|
||||
xfd->rfd, &sa, salen, strerror(errno));
|
||||
Close(xfd->rfd);
|
||||
return STAT_RETRYLATER;
|
||||
} while (true);
|
||||
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,
|
||||
infobuff, sizeof(infobuff)));
|
||||
|
||||
applyopts(xfd->fd1, opts, PH_FD);
|
||||
applyopts(xfd->fd1, opts, PH_CONNECTED);
|
||||
applyopts(xfd->rfd, opts, PH_FD);
|
||||
applyopts(xfd->rfd, opts, PH_CONNECTED);
|
||||
|
||||
if (dofork) {
|
||||
pid_t pid; /* mostly int; only used with fork */
|
||||
if ((pid = xio_fork(false, level==E_ERROR?level:E_WARN)) < 0) {
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->rfd);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
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);
|
||||
xiosetenvulong("PID", cpid, 1);
|
||||
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
if (Close(xfd->rfd) < 0) {
|
||||
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
|
||||
/* !? */
|
||||
@ -318,11 +319,12 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
|
||||
}
|
||||
Info("still listening");
|
||||
} else {
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
if (Close(xfd->rfd) < 0) {
|
||||
Info2("close(%d): %s", xfd->rfd, strerror(errno));
|
||||
}
|
||||
xfd->fd1 = ps;
|
||||
break;
|
||||
if (XIOWITHRD(rw)) xfd->rfd = ps;
|
||||
if (XIOWITHWR(rw)) xfd->wfd = ps;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
|
@ -40,7 +40,7 @@ static int xioopen_nop(int argc, const char *argv[], struct opt *opts,
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
if (xfd->fd1 < 0 && xfd->fd2 < 0) {
|
||||
if (xfd->rfd < 0 && xfd->wfd < 0) { /*!!!*/
|
||||
Error("NOP cannot be endpoint");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
@ -53,7 +53,7 @@ static int xioopen_nop(int argc, const char *argv[], struct opt *opts,
|
||||
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)
|
||||
return result;
|
||||
|
181
xio-openssl.c
181
xio-openssl.c
@ -225,6 +225,7 @@ static int
|
||||
addr_openssl */
|
||||
{
|
||||
struct single *xfd = &xxfd->stream;
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
struct opt *opts0 = NULL;
|
||||
const char *hostname, *portname = NULL;
|
||||
int pf = PF_UNSPEC;
|
||||
@ -282,7 +283,7 @@ static int
|
||||
} else if (argc = 1) {
|
||||
|
||||
/* 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");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
@ -347,86 +348,85 @@ static int
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
}
|
||||
xfd->wfd = xfd->rfd;
|
||||
}
|
||||
|
||||
/*! isn't this too early? */
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0) {
|
||||
return result;
|
||||
}
|
||||
/*! isn't this too early? */
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result =
|
||||
_xioopen_openssl_connect(xfd, opt_ver, xfd->para.openssl.ctx, level);
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
#if WITH_RETRY
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (xfd->forever || xfd->retry) {
|
||||
Close(xfd->fd1);
|
||||
if (xfd->fdtype == FDTYPE_DOUBLE)
|
||||
Close(xfd->fd2);
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
if (result == STAT_RETRYLATER) {
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
}
|
||||
--xfd->retry;
|
||||
continue;
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default: return STAT_NORETRY;
|
||||
}
|
||||
result =
|
||||
_xioopen_openssl_connect(xfd, opt_ver, xfd->para.openssl.ctx, level);
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
#if WITH_RETRY
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (xfd->forever || xfd->retry) {
|
||||
Close(xfd->rfd);
|
||||
Close(xfd->wfd);
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
if (result == STAT_RETRYLATER) {
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
}
|
||||
--xfd->retry;
|
||||
continue;
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default: return STAT_NORETRY;
|
||||
}
|
||||
|
||||
if (dofork) {
|
||||
xiosetchilddied(); /* set SIGCHLD handler */
|
||||
}
|
||||
if (dofork) {
|
||||
xiosetchilddied(); /* set SIGCHLD handler */
|
||||
}
|
||||
|
||||
#if WITH_RETRY
|
||||
if (dofork) {
|
||||
pid_t pid;
|
||||
int level = E_ERROR;
|
||||
if (xfd->forever || xfd->retry) {
|
||||
level = E_WARN;
|
||||
}
|
||||
while ((pid = xio_fork(false, level)) < 0) {
|
||||
if (xfd->forever || --xfd->retry) {
|
||||
Nanosleep(&xfd->intervall, NULL); continue;
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
#if WITH_RETRY
|
||||
if (dofork) {
|
||||
pid_t pid;
|
||||
int level = E_ERROR;
|
||||
if (xfd->forever || xfd->retry) {
|
||||
level = E_WARN;
|
||||
}
|
||||
while ((pid = xio_fork(false, level)) < 0) {
|
||||
if (xfd->forever || --xfd->retry) {
|
||||
Nanosleep(&xfd->intervall, NULL); continue;
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
if (pid == 0) { /* child process */
|
||||
xfd->forever = false; xfd->retry = 0;
|
||||
break;
|
||||
}
|
||||
if (pid == 0) { /* child process */
|
||||
xfd->forever = false; xfd->retry = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
Notice1("forked off child process "F_pid, pid);
|
||||
Close(xfd->fd1);
|
||||
if (xfd->fdtype == FDTYPE_DOUBLE)
|
||||
Close(xfd->fd2);
|
||||
sycSSL_free(xfd->para.openssl.ssl);
|
||||
xfd->para.openssl.ssl = NULL;
|
||||
/* with and without retry */
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
continue; /* with next socket() bind() connect() */
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
break;
|
||||
} while (true); /* drop out on success */
|
||||
/* parent process */
|
||||
Notice1("forked off child process "F_pid, pid);
|
||||
Close(xfd->rfd);
|
||||
Close(xfd->wfd);
|
||||
sycSSL_free(xfd->para.openssl.ssl);
|
||||
xfd->para.openssl.ssl = NULL;
|
||||
/* with and without retry */
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
continue; /* with next socket() bind() connect() */
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
break;
|
||||
} while (true); /* drop out on success */
|
||||
|
||||
Notice1("SSL connection using %s", SSL_get_cipher(xfd->para.openssl.ssl));
|
||||
Notice1("SSL connection using %s", SSL_get_cipher(xfd->para.openssl.ssl));
|
||||
|
||||
/* fill in the fd structure */
|
||||
return STAT_OK;
|
||||
}
|
||||
/* fill in the fd structure */
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
|
||||
/* 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
|
||||
descriptor. this function then performs all SSL related step to make a valid
|
||||
SSL connection from an FD and a CTX. */
|
||||
int _xioopen_openssl_connect(struct single *xfd,
|
||||
/* 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
|
||||
descriptor. this function then performs all SSL related step to make a valid
|
||||
SSL connection from an FD and a CTX. */
|
||||
int _xioopen_openssl_connect(struct single *xfd,
|
||||
bool opt_ver,
|
||||
SSL_CTX *ctx,
|
||||
int level) {
|
||||
@ -542,7 +542,7 @@ static int
|
||||
}
|
||||
|
||||
} else if (argc == 1) {
|
||||
if (xfd->fd1 < 0) {
|
||||
if (xfd->rfd < 0) {
|
||||
Error("openssl-listen without port must be an embedded address");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
@ -590,7 +590,6 @@ static int
|
||||
E_ERROR
|
||||
#endif /* WITH_RETRY */
|
||||
);
|
||||
}
|
||||
/*! not sure if we should try again on retry/forever */
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
@ -611,6 +610,8 @@ static int
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
xfd->wfd = xfd->rfd;
|
||||
}
|
||||
result =
|
||||
_xioopen_openssl_listen(xfd, opt_ver, xfd->para.openssl.ctx, level);
|
||||
switch (result) {
|
||||
@ -1088,31 +1089,35 @@ static int xioSSL_set_fd(struct single *xfd, int level) {
|
||||
unsigned long err;
|
||||
|
||||
/* assign a network connection to the SSL object */
|
||||
if (xfd->fd2 < 0) {
|
||||
if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->fd1) <= 0) {
|
||||
if (xfd->rfd == xfd->wfd) {
|
||||
if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->rfd) <= 0) {
|
||||
Msg(level, "SSL_set_fd() failed");
|
||||
while (err = ERR_get_error()) {
|
||||
Msg2(level, "SSL_set_fd(, %d): %s",
|
||||
xfd->fd2, ERR_error_string(err, NULL));
|
||||
xfd->wfd, ERR_error_string(err, NULL));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} else {
|
||||
if (sycSSL_set_rfd(xfd->para.openssl.ssl, xfd->fd1) <= 0) {
|
||||
Msg(level, "SSL_set_rfd() failed");
|
||||
while (err = ERR_get_error()) {
|
||||
Msg2(level, "SSL_set_rfd(, %d): %s",
|
||||
xfd->fd1, ERR_error_string(err, NULL));
|
||||
if (xfd->rfd >= 0) {
|
||||
if (sycSSL_set_rfd(xfd->para.openssl.ssl, xfd->rfd) <= 0) {
|
||||
Msg(level, "SSL_set_rfd() failed");
|
||||
while (err = ERR_get_error()) {
|
||||
Msg2(level, "SSL_set_rfd(, %d): %s",
|
||||
xfd->rfd, ERR_error_string(err, NULL));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
if (sycSSL_set_wfd(xfd->para.openssl.ssl, xfd->fd2) <= 0) {
|
||||
Msg(level, "SSL_set_wfd() failed");
|
||||
while (err = ERR_get_error()) {
|
||||
Msg2(level, "SSL_set_wfd(, %d): %s",
|
||||
xfd->fd2, ERR_error_string(err, NULL));
|
||||
if (xfd->wfd >= 0) {
|
||||
if (sycSSL_set_wfd(xfd->para.openssl.ssl, xfd->wfd) <= 0) {
|
||||
Msg(level, "SSL_set_wfd() failed");
|
||||
while (err = ERR_get_error()) {
|
||||
Msg2(level, "SSL_set_wfd(, %d): %s",
|
||||
xfd->wfd, ERR_error_string(err, NULL));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
return STAT_OK;
|
||||
|
21
xio-pipe.c
21
xio-pipe.c
@ -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->stream.dtype = XIODATA_2PIPE;
|
||||
sock->stream.fd1 = filedes[0];
|
||||
sock->stream.fd2 = filedes[1];
|
||||
sock->stream.fdtype = FDTYPE_DOUBLE;
|
||||
applyopts_cloexec(sock->stream.fd1, opts);
|
||||
applyopts_cloexec(sock->stream.fd2, opts);
|
||||
sock->stream.rfd = filedes[0];
|
||||
sock->stream.wfd = filedes[1];
|
||||
applyopts_cloexec(sock->stream.rfd, opts);
|
||||
applyopts_cloexec(sock->stream.wfd, opts);
|
||||
|
||||
/* one-time and input-direction options, no second application */
|
||||
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 */
|
||||
if ((result = applyopts(sock->stream.fd1, opts, PH_ALL)) < 0) {
|
||||
if ((result = applyopts(sock->stream.rfd, opts, PH_ALL)) < 0) {
|
||||
return result;
|
||||
}
|
||||
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 */
|
||||
if ((result = applyopts(sock->stream.fd2, opts2, PH_ALL)) < 0)
|
||||
if ((result = applyopts(sock->stream.wfd, opts2, PH_ALL)) < 0)
|
||||
{
|
||||
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) {
|
||||
return result;
|
||||
}
|
||||
fd->stream.fd1 = result;
|
||||
fd->stream.fdtype = FDTYPE_SINGLE;
|
||||
fd->stream.rfd = result;
|
||||
fd->stream.wfd = result;
|
||||
fd->stream.howtoshut = XIOSHUTWR_NONE|XIOSHUTRD_CLOSE;
|
||||
fd->stream.howtoclose = XIOCLOSE_CLOSE;
|
||||
|
||||
applyopts_named(pipename, opts, PH_FD);
|
||||
applyopts(fd->stream.fd1, opts, PH_FD);
|
||||
applyopts_cloexec(fd->stream.fd1, opts);
|
||||
applyopts(fd->stream.rfd, opts, PH_FD);
|
||||
applyopts_cloexec(fd->stream.rfd, opts);
|
||||
return _xio_openlate(&fd->stream, opts);
|
||||
}
|
||||
|
||||
|
1218
xio-progcall.c
1218
xio-progcall.c
File diff suppressed because it is too large
Load Diff
@ -1,35 +1,37 @@
|
||||
/* 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 */
|
||||
|
||||
#ifndef __xio_progcall_h_included
|
||||
#define __xio_progcall_h_included 1
|
||||
|
||||
extern const struct optdesc opt_fdin;
|
||||
extern const struct optdesc opt_fdout;
|
||||
extern const struct optdesc opt_leftfd;
|
||||
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_pipes;
|
||||
extern const struct optdesc opt_pty;
|
||||
extern const struct optdesc opt_openpty;
|
||||
extern const struct optdesc opt_ptmx;
|
||||
extern const struct optdesc opt_commtype;
|
||||
extern const struct optdesc opt_stderr;
|
||||
extern const struct optdesc opt_nofork;
|
||||
extern const struct optdesc opt_sighup;
|
||||
extern const struct optdesc opt_sigint;
|
||||
extern const struct optdesc opt_sigquit;
|
||||
|
||||
extern int _xioopen_foxec_int(int rw, /* O_RDONLY etc. */
|
||||
struct single *fd,
|
||||
unsigned groups,
|
||||
struct opt **opts,
|
||||
int *duptostderr
|
||||
);
|
||||
extern int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
|
||||
struct single *fd,
|
||||
unsigned groups,
|
||||
struct opt **opts,
|
||||
int *duptostderr
|
||||
);
|
||||
extern int
|
||||
_xioopen_progcall(int xioflags, /* XIO_RDONLY etc. */
|
||||
struct single *xfd,
|
||||
unsigned groups,
|
||||
struct opt **opts,
|
||||
int *duptostderr,
|
||||
bool inter,
|
||||
int form
|
||||
);
|
||||
|
||||
extern int setopt_path(struct opt *opts, char **path);
|
||||
extern
|
||||
|
45
xio-proxy.c
45
xio-proxy.c
@ -69,11 +69,11 @@ static ssize_t
|
||||
ssize_t result;
|
||||
do {
|
||||
/* we need at least 16 bytes... */
|
||||
result = Read(xfd->fd1, buff, buflen);
|
||||
result = Read(xfd->rfd, buff, buflen);
|
||||
} while (result < 0 && errno == EINTR); /*! EAGAIN? */
|
||||
if (result < 0) {
|
||||
Msg4(level, "read(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd1, buff, buflen, strerror(errno));
|
||||
xfd->rfd, buff, buflen, strerror(errno));
|
||||
return result;
|
||||
}
|
||||
if (result == 0) {
|
||||
@ -97,7 +97,7 @@ static int xioopen_proxy_connect2(int argc, const char *argv[], struct opt *opts
|
||||
bool dofork = false;
|
||||
int result;
|
||||
|
||||
if (xfd->fd1 < 0) {
|
||||
if (xfd->rfd < 0) {
|
||||
Error("xioopen_proxy_connect(): proxyname missing");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
@ -118,10 +118,9 @@ static int xioopen_proxy_connect2(int argc, const char *argv[], struct opt *opts
|
||||
Notice2("opening connection to %s:%u using proxy CONNECT",
|
||||
proxyvars->targetaddr, proxyvars->targetport);
|
||||
|
||||
xfd->dtype = XIODATA_STREAM;
|
||||
xfd->fdtype = FDTYPE_DOUBLE;
|
||||
xfd->dtype = XIODATA_STREAM;
|
||||
|
||||
applyopts(xfd->fd1, opts, PH_ALL);
|
||||
applyopts(xfd->rfd, opts, PH_ALL);
|
||||
/*!*/
|
||||
|
||||
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) {
|
||||
/* we expect the form: host:host:port */
|
||||
struct single *xfd = &xxfd->stream;
|
||||
int rw = (xioflags & XIO_ACCMODE);
|
||||
struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars;
|
||||
const char *proxyname;
|
||||
char *proxyport = NULL;
|
||||
@ -165,7 +165,7 @@ static int xioopen_proxy_connect3(int argc, const char *argv[], struct opt *opts
|
||||
int level;
|
||||
int result;
|
||||
|
||||
if (xfd->fd1 >= 0) {
|
||||
if (xfd->rfd >= 0) {
|
||||
Error("xioopen_proxy_connect(): proxyname not allowed here");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
@ -233,8 +233,10 @@ static int xioopen_proxy_connect3(int argc, const char *argv[], struct opt *opts
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
xfd->fdtype = FDTYPE_SINGLE;
|
||||
applyopts(xfd->fd1, opts, PH_ALL);
|
||||
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
|
||||
if (!XIOWITHRD(rw)) xfd->rfd = -1;
|
||||
|
||||
applyopts(xfd->rfd, opts, PH_ALL);
|
||||
/*!*/
|
||||
|
||||
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 */
|
||||
Notice1("forked off child process "F_pid, pid);
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->fd2);
|
||||
Close(xfd->rfd);
|
||||
Close(xfd->wfd);
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
continue;
|
||||
@ -345,7 +347,6 @@ int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts,
|
||||
int _xioopen_proxy_connect(struct single *xfd,
|
||||
struct proxyvars *proxyvars,
|
||||
int level) {
|
||||
int wfd;
|
||||
size_t offset;
|
||||
char request[CONNLEN];
|
||||
char buff[BUFLEN+1];
|
||||
@ -357,8 +358,6 @@ int _xioopen_proxy_connect(struct single *xfd,
|
||||
int state;
|
||||
ssize_t sresult;
|
||||
|
||||
wfd = (xfd->fdtype == FDTYPE_SINGLE ? xfd->fd1 : xfd->fd2);
|
||||
|
||||
/* generate proxy request header - points to final target */
|
||||
sprintf(request, "CONNECT %s:%u HTTP/1.0\r\n",
|
||||
proxyvars->targetaddr, proxyvars->targetport);
|
||||
@ -368,13 +367,13 @@ int _xioopen_proxy_connect(struct single *xfd,
|
||||
Info1("sending \"%s\"", textbuff);
|
||||
/* write errors are assumed to always be hard errors, no retry */
|
||||
do {
|
||||
sresult = Write(wfd, request, strlen(request));
|
||||
sresult = Write(xfd->wfd, request, strlen(request));
|
||||
} while (sresult < 0 && errno == EINTR);
|
||||
if (sresult < 0) {
|
||||
Msg4(level, "write(%d, %p, "F_Zu"): %s",
|
||||
wfd, request, strlen(request), strerror(errno));
|
||||
if (Close(wfd) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
xfd->wfd, request, strlen(request), strerror(errno));
|
||||
if (Close(xfd->wfd) < 0) {
|
||||
Info2("close(%d): %s", xfd->wfd, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
@ -401,13 +400,13 @@ int _xioopen_proxy_connect(struct single *xfd,
|
||||
Info1("sending \"%s\\r\\n\"", header);
|
||||
*next++ = '\r'; *next++ = '\n'; *next++ = '\0';
|
||||
do {
|
||||
sresult = Write(wfd, header, strlen(header));
|
||||
sresult = Write(xfd->wfd, header, strlen(header));
|
||||
} while (sresult < 0 && errno == EINTR);
|
||||
if (sresult < 0) {
|
||||
Msg4(level, "write(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd2, header, strlen(header), strerror(errno));
|
||||
if (Close(wfd/*!*/) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
xfd->wfd, header, strlen(header), strerror(errno));
|
||||
if (Close(xfd->wfd/*!*/) < 0) {
|
||||
Info2("close(%d): %s", xfd->wfd, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
@ -417,7 +416,7 @@ int _xioopen_proxy_connect(struct single *xfd,
|
||||
|
||||
Info("sending \"\\r\\n\"");
|
||||
do {
|
||||
sresult = Write(wfd, "\r\n", 2);
|
||||
sresult = Write(xfd->wfd, "\r\n", 2);
|
||||
} while (sresult < 0 && errno == EINTR);
|
||||
/*! */
|
||||
|
||||
|
@ -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) {
|
||||
/* we expect the form: filename */
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
int ptyfd = -1, ttyfd = -1;
|
||||
#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
|
||||
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);/*!*/
|
||||
xfd->stream.dtype = XIODATA_PTY;
|
||||
xfd->stream.fdtype = FDTYPE_SINGLE;
|
||||
|
||||
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);
|
||||
if (applyopts_single(&xfd->stream, opts, PH_LATE) < 0) return -1;
|
||||
|
||||
|
18
xio-rawip.c
18
xio-rawip.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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) {
|
||||
char *garbage;
|
||||
xiosingle_t *xfd = &xxfd->stream;
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
union sockaddr_union us;
|
||||
socklen_t uslen;
|
||||
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);
|
||||
|
||||
xfd->fdtype = FDTYPE_SINGLE;
|
||||
xfd->dtype = XIODATA_RECVFROM_SKIPIP;
|
||||
|
||||
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) {
|
||||
needbind = true;
|
||||
}
|
||||
return
|
||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||
opts, xioflags, xfd, groups, *pf, socktype, ipproto);
|
||||
if ((result =
|
||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||
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;
|
||||
}
|
||||
|
||||
xfd->stream.fdtype = FDTYPE_SINGLE;
|
||||
xfd->stream.dtype = XIODATA_RECVFROM_SKIPIP_ONE;
|
||||
if ((result =
|
||||
_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.fdtype = FDTYPE_SINGLE;
|
||||
xfd->stream.dtype = XIODATA_RECV_SKIPIP;
|
||||
result =
|
||||
_xioopen_dgram_recv(&xfd->stream, xioflags,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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;
|
||||
|
||||
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');
|
||||
|
||||
if ((rw+1)&2)
|
||||
if (XIOWITHWR(rw))
|
||||
strcpy(cp, " and "); cp = strchr(cp, '\0');
|
||||
}
|
||||
if ((rw+1)&2) {
|
||||
if (XIOWITHWR(rw)) {
|
||||
strcpy(cp, "stdio for writing"); cp = strchr(cp, '\0');
|
||||
}
|
||||
Notice(msgbuf);
|
||||
|
||||
xfd->stream.fd1 = 0; /* stdin */
|
||||
if ((rw+1) & 2) {
|
||||
xfd->stream.fd2 = 1; /* stdout */
|
||||
xfd->stream.rfd = 0; /* stdin */
|
||||
if (XIOWITHWR(rw)) {
|
||||
xfd->stream.wfd = 1; /* stdout */
|
||||
}
|
||||
xfd->stream.howtoclose = XIOCLOSE_READLINE;
|
||||
xfd->stream.dtype = XIODATA_READLINE;
|
||||
xfd->stream.fdtype = FDTYPE_DOUBLE;
|
||||
|
||||
#if WITH_TERMIOS
|
||||
if (Isatty(xfd->stream.fd1)) {
|
||||
if (Tcgetattr(xfd->stream.fd1, &xfd->stream.savetty) < 0) {
|
||||
if (Isatty(xfd->stream.rfd)) {
|
||||
if (Tcgetattr(xfd->stream.rfd, &xfd->stream.savetty) < 0) {
|
||||
Warn2("cannot query current terminal settings on fd %d. %s",
|
||||
xfd->stream.fd1, strerror(errno));
|
||||
xfd->stream.rfd, strerror(errno));
|
||||
} else {
|
||||
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;
|
||||
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();
|
||||
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);
|
||||
}
|
||||
#if _WITH_TERMIOS
|
||||
xiotermios_clrflag(xfd->stream.fd1, 3, ICANON);
|
||||
xiotermios_clrflag(xfd->stream.fd1, 3, ECHO);
|
||||
xiotermios_clrflag(xfd->stream.rfd, 3, ICANON);
|
||||
xiotermios_clrflag(xfd->stream.rfd, 3, ECHO);
|
||||
#endif /* _WITH_TERMIOS */
|
||||
return _xio_openlate(&xfd->stream, opts);
|
||||
}
|
||||
@ -153,45 +152,45 @@ ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) {
|
||||
readline */
|
||||
struct termios saveterm, setterm;
|
||||
*pipe->para.readline.dynend = '\0';
|
||||
Tcgetattr(pipe->fd1, &saveterm); /*! error */
|
||||
Tcgetattr(pipe->rfd, &saveterm); /*! error */
|
||||
setterm = saveterm;
|
||||
setterm.c_lflag |= ICANON;
|
||||
Tcsetattr(pipe->fd1, TCSANOW, &setterm); /*!*/
|
||||
Tcsetattr(pipe->rfd, TCSANOW, &setterm); /*!*/
|
||||
#endif /* _WITH_TERMIOS */
|
||||
do {
|
||||
bytes = Read(pipe->fd1, buff, bufsiz);
|
||||
bytes = Read(pipe->rfd, buff, bufsiz);
|
||||
} while (bytes < 0 && errno == EINTR);
|
||||
if (bytes < 0) {
|
||||
_errno = errno;
|
||||
Error4("read(%d, %p, "F_Zu"): %s",
|
||||
pipe->fd1, buff, bufsiz, strerror(_errno));
|
||||
pipe->rfd, buff, bufsiz, strerror(_errno));
|
||||
errno = _errno;
|
||||
return -1;
|
||||
}
|
||||
#if _WITH_TERMIOS
|
||||
setterm.c_lflag &= ~ICANON;
|
||||
Tcgetattr(pipe->fd1, &setterm); /*! error */
|
||||
Tcsetattr(pipe->fd1, TCSANOW, &saveterm); /*!*/
|
||||
Tcgetattr(pipe->rfd, &setterm); /*! error */
|
||||
Tcsetattr(pipe->rfd, TCSANOW, &saveterm); /*!*/
|
||||
#endif /* _WITH_TERMIOS */
|
||||
pipe->para.readline.dynend = pipe->para.readline.dynprompt;
|
||||
/*Write(pipe->fd1, "\n", 1);*/ /*!*/
|
||||
/*Write(pipe->rfd, "\n", 1);*/ /*!*/
|
||||
return bytes;
|
||||
}
|
||||
#endif /* HAVE_REGEX_H */
|
||||
|
||||
#if _WITH_TERMIOS
|
||||
xiotermios_setflag(pipe->fd1, 3, ECHO);
|
||||
xiotermios_setflag(pipe->rfd, 3, ECHO);
|
||||
#endif /* _WITH_TERMIOS */
|
||||
if (pipe->para.readline.prompt || pipe->para.readline.dynprompt) {
|
||||
/* we must carriage return, because readline will first print the
|
||||
prompt */
|
||||
ssize_t writt;
|
||||
do {
|
||||
writt = Write(pipe->fd1, "\r", 1);
|
||||
writt = Write(pipe->rfd, "\r", 1);
|
||||
} while (writt < 0 && errno == EINTR);
|
||||
if (writt < 0) {
|
||||
Warn2("write(%d, \"\\r\", 1): %s",
|
||||
pipe->fd1, strerror(errno));
|
||||
pipe->rfd, strerror(errno));
|
||||
} else if (writt < 1) {
|
||||
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 */
|
||||
}
|
||||
#if _WITH_TERMIOS
|
||||
xiotermios_clrflag(pipe->fd1, 3, ECHO);
|
||||
xiotermios_clrflag(pipe->rfd, 3, ECHO);
|
||||
#endif /* _WITH_TERMIOS */
|
||||
Add_history(line);
|
||||
bytes = strlen(line);
|
||||
|
202
xio-socket.c
202
xio-socket.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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 dummy1, int dummy2, int dummy3) {
|
||||
struct single *xfd = &xxfd->stream;
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
const char *pfname = argv[1];
|
||||
const char *protname = argv[2];
|
||||
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) {
|
||||
return result;
|
||||
}
|
||||
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
|
||||
if (!XIOWITHRD(rw)) xfd->rfd = -1;
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0) {
|
||||
return result;
|
||||
}
|
||||
@ -382,6 +385,7 @@ static
|
||||
int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd, unsigned groups,
|
||||
int dummy1, int dummy2, int dummy3) {
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
int result;
|
||||
|
||||
if (argc != 5) {
|
||||
@ -396,15 +400,22 @@ int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts,
|
||||
return result;
|
||||
}
|
||||
_xio_openlate(&xxfd->stream, opts);
|
||||
if (XIOWITHWR(rw)) xxfd->stream.wfd = xxfd->stream.rfd;
|
||||
if (!XIOWITHRD(rw)) xxfd->stream.rfd = -1;
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
returns the resulting FD in xfd->rfd, independend of xioflags
|
||||
*/
|
||||
static
|
||||
int _xioopen_socket_sendto(const char *pfname, const char *type,
|
||||
const char *protname, const char *address,
|
||||
struct opt *opts, int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups) {
|
||||
xiosingle_t *xfd = &xxfd->stream;
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
char *garbage;
|
||||
union sockaddr_union us = {{0}};
|
||||
socklen_t uslen = 0;
|
||||
@ -484,9 +495,15 @@ int _xioopen_socket_sendto(const char *pfname, const char *type,
|
||||
needbind = true;
|
||||
}
|
||||
|
||||
return
|
||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||
opts, xioflags, xfd, groups, pf, socktype, proto);
|
||||
if ((result =
|
||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||
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
|
||||
to a peer address.
|
||||
might fork.
|
||||
returns the resulting FD in xfd->rfd
|
||||
applies and consumes the following options:
|
||||
PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
|
||||
PH_CONNECTED, PH_LATE,
|
||||
@ -741,19 +759,18 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||
int _errno;
|
||||
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;
|
||||
}
|
||||
xfd->fdtype = FDTYPE_SINGLE;
|
||||
|
||||
applyopts_offset(xfd, opts);
|
||||
applyopts(xfd->fd1, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->fd1, opts, PH_FD);
|
||||
applyopts(xfd->rfd, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->rfd, opts, PH_FD);
|
||||
|
||||
applyopts_cloexec(xfd->fd1, opts);
|
||||
applyopts_cloexec(xfd->rfd, opts);
|
||||
|
||||
applyopts(xfd->fd1, opts, PH_PREBIND);
|
||||
applyopts(xfd->fd1, opts, PH_BIND);
|
||||
applyopts(xfd->rfd, opts, PH_PREBIND);
|
||||
applyopts(xfd->rfd, opts, PH_BIND);
|
||||
#if WITH_TCP || WITH_UDP
|
||||
if (alt) {
|
||||
union sockaddr_union sin, *sinp;
|
||||
@ -810,13 +827,13 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||
problem = false;
|
||||
do { /* loop over lowport bind() attempts */
|
||||
*port = htons(i);
|
||||
if (Bind(xfd->fd1, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) {
|
||||
if (Bind(xfd->rfd, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) {
|
||||
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)),
|
||||
sizeof(*sinp), strerror(errno));
|
||||
if (errno != EADDRINUSE) {
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->rfd);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} else {
|
||||
@ -826,7 +843,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||
if (i == N) {
|
||||
Msg(level, "no low port available");
|
||||
/*errno = EADDRINUSE; still assigned */
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->rfd);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} while (i != N);
|
||||
@ -834,31 +851,31 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||
#endif /* WITH_TCP || WITH_UDP */
|
||||
|
||||
if (us) {
|
||||
if (Bind(xfd->fd1, us, uslen) < 0) {
|
||||
if (Bind(xfd->rfd, us, uslen) < 0) {
|
||||
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));
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->rfd);
|
||||
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 ||
|
||||
xfd->para.socket.connect_timeout.tv_usec != 0) {
|
||||
fcntl_flags = Fcntl(xfd->fd1, F_GETFL);
|
||||
Fcntl_l(xfd->fd1, F_SETFL, fcntl_flags|O_NONBLOCK);
|
||||
fcntl_flags = Fcntl(xfd->rfd, F_GETFL);
|
||||
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;
|
||||
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",
|
||||
xfd->fd1, &la.soa, lalen, strerror(errno));
|
||||
xfd->rfd, &la.soa, lalen, strerror(errno));
|
||||
}
|
||||
errno = _errno;
|
||||
if (result < 0) {
|
||||
@ -870,15 +887,15 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||
int result;
|
||||
|
||||
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));
|
||||
timeout = xfd->para.socket.connect_timeout;
|
||||
writefd.fd = xfd->fd1;
|
||||
writefd.fd = xfd->rfd;
|
||||
writefd.events = (POLLIN|POLLHUP|POLLERR);
|
||||
result = xiopoll(&writefd, 1, &timeout);
|
||||
if (result < 0) {
|
||||
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;
|
||||
}
|
||||
if (result == 0) {
|
||||
@ -890,23 +907,23 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||
if (writefd.revents & POLLOUT) {
|
||||
#if 0
|
||||
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",
|
||||
sockaddr_info(them, infobuff, sizeof(infobuff)),
|
||||
strerror(errno));
|
||||
#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",
|
||||
xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||
xfd->rfd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||
themlen, strerror(errno));
|
||||
#endif
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
/* otherwise OK */
|
||||
Fcntl_l(xfd->fd1, F_SETFL, fcntl_flags);
|
||||
Fcntl_l(xfd->rfd, F_SETFL, fcntl_flags);
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
} 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 */
|
||||
int _errno = errno;
|
||||
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));
|
||||
#if 0
|
||||
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);
|
||||
#endif
|
||||
/*!!! and remove bind socket */
|
||||
Close(xfd->fd1); xfd->fd1 = -1;
|
||||
Close(xfd->rfd); xfd->rfd = -1;
|
||||
errno = _errno;
|
||||
return -1;
|
||||
} else {
|
||||
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));
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->rfd);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
|
||||
applyopts_fchown(xfd->fd1, opts); /* OPT_USER, OPT_GROUP */
|
||||
applyopts(xfd->fd1, opts, PH_CONNECTED);
|
||||
applyopts(xfd->fd1, opts, PH_LATE);
|
||||
applyopts_fchown(xfd->rfd, opts); /* OPT_USER, OPT_GROUP */
|
||||
applyopts(xfd->rfd, opts, PH_CONNECTED);
|
||||
applyopts(xfd->rfd, opts, PH_LATE);
|
||||
|
||||
Notice1("successfully connected from local address %s",
|
||||
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,
|
||||
OFUNC_OFFSET,
|
||||
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.
|
||||
*/
|
||||
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 */
|
||||
Notice1("forked off child process "F_pid, pid);
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->rfd);
|
||||
/* with and without retry */
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
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
|
||||
OFUNC_OFFSET
|
||||
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 */
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
applyopts_offset(xfd, opts);
|
||||
applyopts_single(xfd, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->fd1, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->fd1, opts, PH_FD);
|
||||
applyopts(xfd->rfd, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->rfd, opts, PH_FD);
|
||||
|
||||
applyopts_cloexec(xfd->fd1, opts);
|
||||
applyopts_cloexec(xfd->rfd, opts);
|
||||
|
||||
applyopts(xfd->fd1, opts, PH_PREBIND);
|
||||
applyopts(xfd->fd1, opts, PH_BIND);
|
||||
applyopts(xfd->rfd, opts, PH_PREBIND);
|
||||
applyopts(xfd->rfd, opts, PH_BIND);
|
||||
|
||||
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",
|
||||
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));
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->rfd);
|
||||
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",
|
||||
xfd->fd1, &la.soa, lalen, strerror(errno));
|
||||
xfd->rfd, &la.soa, lalen, strerror(errno));
|
||||
}
|
||||
|
||||
applyopts_fchown(xfd->fd1, opts);
|
||||
applyopts(xfd->fd1, opts, PH_CONNECTED);
|
||||
applyopts(xfd->fd1, opts, PH_LATE);
|
||||
applyopts_fchown(xfd->rfd, opts);
|
||||
applyopts(xfd->rfd, opts, PH_CONNECTED);
|
||||
applyopts(xfd->rfd, opts, PH_LATE);
|
||||
|
||||
/* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */
|
||||
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 opt *opts,
|
||||
int pf, int socktype, int proto, int level) {
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
int s;
|
||||
char *rangename;
|
||||
socklen_t salen;
|
||||
bool dofork = false;
|
||||
@ -1258,22 +1279,24 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||
}
|
||||
#endif /* 1 */
|
||||
|
||||
if ((xfd->fd1 = xiosocket(opts, pf, socktype, proto, level)) < 0) {
|
||||
if ((s = xiosocket(opts, pf, socktype, proto, level)) < 0) {
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
if (XIOWITHRD(rw)) xfd->rfd = s;
|
||||
if (XIOWITHWR(rw)) xfd->wfd = s;
|
||||
|
||||
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->fd1, opts, PH_BIND);
|
||||
if ((us != NULL) && Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1,
|
||||
applyopts(xfd->rfd, opts, PH_PREBIND);
|
||||
applyopts(xfd->rfd, opts, PH_BIND);
|
||||
if ((us != NULL) && Bind(xfd->rfd, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->rfd,
|
||||
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
|
||||
strerror(errno));
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->rfd);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
@ -1283,7 +1306,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||
}
|
||||
#endif
|
||||
|
||||
applyopts(xfd->fd1, opts, PH_PASTBIND);
|
||||
applyopts(xfd->rfd, opts, PH_PASTBIND);
|
||||
#if WITH_UNIX
|
||||
if (pf == AF_UNIX && us != NULL) {
|
||||
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
|
||||
@ -1368,7 +1391,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||
if (drop) {
|
||||
char *dummy[2];
|
||||
|
||||
Recv(xfd->fd1, dummy, sizeof(dummy), 0);
|
||||
Recv(xfd->rfd, dummy, sizeof(dummy), 0);
|
||||
drop = true;
|
||||
}
|
||||
|
||||
@ -1381,7 +1404,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||
} else {
|
||||
Notice1("receiving IP protocol %u", proto);
|
||||
}
|
||||
readfd.fd = xfd->fd1;
|
||||
readfd.fd = xfd->rfd;
|
||||
readfd.events = POLLIN;
|
||||
if (xiopoll(&readfd, 1, NULL) > 0) {
|
||||
break;
|
||||
@ -1391,8 +1414,8 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||
continue;
|
||||
}
|
||||
|
||||
Msg2(level, "xiopoll({%d,,},,-1): %s", xfd->fd1, strerror(errno));
|
||||
Close(xfd->fd1);
|
||||
Msg2(level, "xiopoll({%d,,},,-1): %s", xfd->rfd, strerror(errno));
|
||||
Close(xfd->rfd);
|
||||
return STAT_RETRYLATER;
|
||||
} while (true);
|
||||
|
||||
@ -1404,7 +1427,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
|
||||
msgh.msg_controllen = sizeof(ctrlbuff);
|
||||
#endif
|
||||
if (xiogetpacketsrc(xfd->fd1, &msgh) < 0) {
|
||||
if (xiogetpacketsrc(xfd->rfd, &msgh) < 0) {
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
palen = msgh.msg_namelen;
|
||||
@ -1418,7 +1441,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||
if (xiocheckpeer(xfd, pa, la) < 0) {
|
||||
/* drop packet */
|
||||
char buff[512];
|
||||
Recv(xfd->fd1, buff, sizeof(buff), 0);
|
||||
Recv(xfd->rfd, buff, sizeof(buff), 0);
|
||||
continue;
|
||||
}
|
||||
Info1("permitting packet from %s",
|
||||
@ -1429,9 +1452,9 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||
/*xiosetsockaddrenv("SOCK", la, lalen, 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->salen = palen;
|
||||
@ -1450,7 +1473,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||
Sigprocmask(SIG_BLOCK, &mask_sigchldusr1, NULL);
|
||||
|
||||
if ((pid = xio_fork(false, level)) < 0) {
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->rfd);
|
||||
Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
@ -1505,27 +1528,31 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
|
||||
struct sockaddr *us, socklen_t uslen,
|
||||
struct opt *opts, int pf, int socktype, int proto,
|
||||
int level) {
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
int s;
|
||||
char *rangename;
|
||||
char infobuff[256];
|
||||
|
||||
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;
|
||||
}
|
||||
if (XIOWITHRD(rw)) xfd->rfd = s;
|
||||
if (XIOWITHWR(rw)) xfd->wfd = s;
|
||||
|
||||
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->fd1, opts, PH_BIND);
|
||||
if ((us != NULL) && Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1,
|
||||
applyopts(xfd->rfd, opts, PH_PREBIND);
|
||||
applyopts(xfd->rfd, opts, PH_BIND);
|
||||
if ((us != NULL) && Bind(xfd->rfd, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->rfd,
|
||||
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
|
||||
strerror(errno));
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->rfd);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
@ -1535,7 +1562,7 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
|
||||
}
|
||||
#endif
|
||||
|
||||
applyopts(xfd->fd1, opts, PH_PASTBIND);
|
||||
applyopts(xfd->rfd, opts, PH_PASTBIND);
|
||||
#if WITH_UNIX
|
||||
if (pf == AF_UNIX && us != NULL) {
|
||||
/*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_PROTOTYPE, &proto);
|
||||
result = Socketpair(pf, socktype, proto, sv);
|
||||
if (result < 0) {
|
||||
Error5("socketpair(%d, %d, %d, %p): %s",
|
||||
pf, socktype, proto, sv, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
result = xiosocketpair2(pf, socktype, proto, sv);
|
||||
return result;
|
||||
}
|
||||
|
39
xio-socks.c
39
xio-socks.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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) {
|
||||
/* we expect the form: host:host:port */
|
||||
struct single *xfd = &xxfd->stream;
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
struct opt *opts0 = NULL;
|
||||
const char *sockdname; char *sockdport;
|
||||
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 (xfd->fd1 < 0) {
|
||||
if (xfd->rfd < 0) {
|
||||
Error("xioopen_socks4_connect(): socksservername missing");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
@ -94,7 +95,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
||||
targetname = argv[1];
|
||||
targetport = argv[2];
|
||||
} else /* if (argc == 4) */ {
|
||||
if (xfd->fd1 >= 0) {
|
||||
if (xfd->rfd >= 0) {
|
||||
Error("xioopen_socks4_connect(): socksservername not allowed here");
|
||||
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);
|
||||
if (result != STAT_OK) return result;
|
||||
if (xfd->fd2 < 0) {
|
||||
if (xfd->wfd < 0) {
|
||||
result =
|
||||
_xioopen_ipapp_prepare(opts, &opts0, sockdname, sockdport,
|
||||
&pf, ipproto,
|
||||
@ -159,7 +160,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
||||
return result;
|
||||
}
|
||||
|
||||
if (xfd->fd2 < 0) {
|
||||
if (xfd->wfd < 0) {
|
||||
/* this cannot fork because we retrieved fork option above */
|
||||
result =
|
||||
_xioopen_connect (xfd,
|
||||
@ -179,14 +180,14 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
xfd->fdtype = FDTYPE_SINGLE;
|
||||
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
|
||||
if (!XIOWITHRD(rw)) xfd->rfd = -1;
|
||||
} else {
|
||||
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)
|
||||
return result;
|
||||
@ -233,8 +234,8 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
||||
|
||||
/* parent process */
|
||||
Notice1("forked off child process "F_pid, pid);
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->fd2);
|
||||
Close(xfd->rfd);
|
||||
Close(xfd->wfd);
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
continue;
|
||||
@ -348,7 +349,7 @@ int _xioopen_socks4_connect(struct single *xfd,
|
||||
struct socks4head *replyhead = (struct socks4head *)buff;
|
||||
char *destdomname = NULL;
|
||||
|
||||
wfd = (xfd->fdtype == FDTYPE_SINGLE ? xfd->fd1 : xfd->fd2);
|
||||
wfd =xfd->wfd;
|
||||
|
||||
/* send socks header (target addr+port, +auth) */
|
||||
#if WITH_MSGLEVEL <= E_INFO
|
||||
@ -384,8 +385,8 @@ int _xioopen_socks4_connect(struct single *xfd,
|
||||
if (Close(wfd) < 0) {
|
||||
Info2("close(%d): %s", wfd, strerror(errno));
|
||||
}
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
if (Close(xfd->rfd) < 0) {
|
||||
Info2("close(%d): %s", xfd->rfd, strerror(errno));
|
||||
}
|
||||
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 */
|
||||
/* receive socks answer */
|
||||
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);
|
||||
if (result < 0) {
|
||||
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));
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
if (Close(xfd->rfd) < 0) {
|
||||
Info2("close(%d): %s", xfd->rfd, strerror(errno));
|
||||
}
|
||||
if (Close(wfd) < 0) {
|
||||
Info2("close(%d): %s", wfd, strerror(errno));
|
||||
@ -410,8 +411,8 @@ int _xioopen_socks4_connect(struct single *xfd,
|
||||
}
|
||||
if (result == 0) {
|
||||
Msg(level, "read(): EOF during read of socks reply, peer might not be a socks4 server");
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
if (Close(xfd->rfd) < 0) {
|
||||
Info2("close(%d): %s", xfd->rfd, strerror(errno));
|
||||
}
|
||||
if (Close(wfd) < 0) {
|
||||
Info2("close(%d): %s", wfd, strerror(errno));
|
||||
|
64
xio-socks5.c
64
xio-socks5.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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 */
|
||||
Debug("waiting for data from peer");
|
||||
do {
|
||||
result = Read(xfd->fd1, buff+bytes, buflen-bytes);
|
||||
result = Read(xfd->rfd, buff+bytes, buflen-bytes);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
if (result < 0) {
|
||||
Msg4(level, "read(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd1, buff+bytes, buflen-bytes,
|
||||
xfd->rfd, buff+bytes, buflen-bytes,
|
||||
strerror(errno));
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
if (Close(xfd->rfd) < 0) {
|
||||
Warn2("close(%d): %s", xfd->rfd, strerror(errno));
|
||||
}
|
||||
if (Close(xfd->fd2) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
if (Close(xfd->wfd) < 0) {
|
||||
Warn2("close(%d): %s", xfd->wfd, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
if (result == 0) {
|
||||
Msg(level, "read(): EOF during read of socks reply");
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
if (Close(xfd->rfd) < 0) {
|
||||
Warn2("close(%d): %s", xfd->rfd, strerror(errno));
|
||||
}
|
||||
if (Close(xfd->fd2) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
if (Close(xfd->wfd) < 0) {
|
||||
Warn2("close(%d): %s", xfd->wfd, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
@ -107,7 +107,7 @@ static int xioopen_socks5_client(int argc, const char *argv[],
|
||||
if (result != STAT_OK) return result;
|
||||
#endif
|
||||
|
||||
if (xfd->fd1 < 0) {
|
||||
if (xfd->rfd < 0) {
|
||||
Error("socks5 must be used as embedded address");
|
||||
return -1;
|
||||
}
|
||||
@ -166,7 +166,7 @@ static int xioopen_socks5_client(int argc, const char *argv[],
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
xfd->fd1 = xfd->fd2 = xfd->fd;
|
||||
xfd->fd1 = xfd->wfd = xfd->fd;
|
||||
} else
|
||||
#endif
|
||||
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)
|
||||
return result;
|
||||
@ -236,16 +236,16 @@ int _xioopen_socks5_connect(struct single *xfd,
|
||||
/* send socks header (target addr+port, +auth) */
|
||||
Info("sending socks5 identifier/method selection message");
|
||||
do {
|
||||
result = Write(xfd->fd2, sendmethod, sendlen);
|
||||
result = Write(xfd->wfd, sendmethod, sendlen);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
if (result < 0) {
|
||||
Msg4(level, "write(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd2, sendmethod, sendlen, strerror(errno));
|
||||
if (Close(xfd->fd2) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
xfd->wfd, sendmethod, sendlen, strerror(errno));
|
||||
if (Close(xfd->wfd) < 0) {
|
||||
Warn2("close(%d): %s", xfd->wfd, strerror(errno));
|
||||
}
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
if (Close(xfd->rfd) < 0) {
|
||||
Warn2("close(%d): %s", xfd->rfd, strerror(errno));
|
||||
}
|
||||
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) */
|
||||
Info("sending socks5 request selection");
|
||||
do {
|
||||
result = Write(xfd->fd2, sendrequest, sendlen);
|
||||
result = Write(xfd->wfd, sendrequest, sendlen);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
if (result < 0) {
|
||||
Msg4(level, "write(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd2, sendmethod, sendlen, strerror(errno));
|
||||
if (Close(xfd->fd2) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
xfd->wfd, sendmethod, sendlen, strerror(errno));
|
||||
if (Close(xfd->wfd) < 0) {
|
||||
Warn2("close(%d): %s", xfd->wfd, strerror(errno));
|
||||
}
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
if (Close(xfd->rfd) < 0) {
|
||||
Warn2("close(%d): %s", xfd->rfd, strerror(errno));
|
||||
}
|
||||
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) */
|
||||
Info1("sending socks5 %s message", descr);
|
||||
do {
|
||||
result = Write(xfd->fd2, sendbuff, sendlen);
|
||||
result = Write(xfd->wfd, sendbuff, sendlen);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
if (result < 0) {
|
||||
Msg4(level, "write(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd2, sendbuff, sendlen, strerror(errno));
|
||||
if (Close(xfd->fd2) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
xfd->wfd, sendbuff, sendlen, strerror(errno));
|
||||
if (Close(xfd->wfd) < 0) {
|
||||
Warn2("close(%d): %s", xfd->wfd, strerror(errno));
|
||||
}
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
if (Close(xfd->rfd) < 0) {
|
||||
Warn2("close(%d): %s", xfd->rfd, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER; /* retry complete open cycle */
|
||||
}
|
||||
|
48
xio-stdio.c
48
xio-stdio.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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
|
||||
changed parsing mechanism does not allow us to check the type of FD before
|
||||
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_stdin0 = { XIOADDR_SYS, "stdin", 0, XIOBIT_RDONLY, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_stdfd, 0, 0, 0 HELP(NULL) };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_stdout0 = { XIOADDR_SYS, "stdout", 0, XIOBIT_WRONLY, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_stdfd, 1, 0, 0 HELP(NULL) };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_stderr0 = { XIOADDR_SYS, "stderr", 0, XIOBIT_WRONLY, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_stdfd, 2, 0, 0 HELP(NULL) };
|
||||
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_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_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_UNSPEC, XIOCLOSE_NONE, xioopen_stdfd, 2, 0, 0 HELP(NULL) };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_stdio[] = {
|
||||
(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;
|
||||
int result;
|
||||
|
||||
sock->stream.fd1 = 0 /*stdin*/;
|
||||
sock->stream.fd2 = 1 /*stdout*/;
|
||||
sock->stream.fdtype = FDTYPE_DOUBLE;
|
||||
sock->stream.rfd = 0 /*stdin*/;
|
||||
sock->stream.wfd = 1 /*stdout*/;
|
||||
|
||||
#if WITH_TERMIOS
|
||||
if (Isatty(sock->stream.fd1)) {
|
||||
if (Tcgetattr(sock->stream.fd1,
|
||||
if (Isatty(sock->stream.rfd)) {
|
||||
if (Tcgetattr(sock->stream.rfd,
|
||||
&sock->stream.savetty)
|
||||
< 0) {
|
||||
Warn2("cannot query current terminal settings on fd %d: %s",
|
||||
sock->stream.fd1, strerror(errno));
|
||||
sock->stream.rfd, strerror(errno));
|
||||
} else {
|
||||
sock->stream.ttyvalid = true;
|
||||
}
|
||||
}
|
||||
if (Isatty(sock->stream.fd2)) {
|
||||
if (Tcgetattr(sock->stream.fd2,
|
||||
if (Isatty(sock->stream.wfd) && (sock->stream.wfd != sock->stream.rfd)) {
|
||||
if (Tcgetattr(sock->stream.wfd,
|
||||
&sock->stream.savetty)
|
||||
< 0) {
|
||||
Warn2("cannot query current terminal settings on fd %d: %s",
|
||||
|
||||
sock->stream.fd2, strerror(errno));
|
||||
sock->stream.wfd, strerror(errno));
|
||||
} else {
|
||||
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)
|
||||
return -1;
|
||||
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 */
|
||||
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 */
|
||||
if ((result = applyopts(sock->stream.fd1, opts1, PH_ALL)) < 0) {
|
||||
if ((result = applyopts(sock->stream.rfd, opts1, PH_ALL)) < 0) {
|
||||
return result;
|
||||
}
|
||||
if ((result = _xio_openlate(&sock->stream, opts1)) < 0) {
|
||||
@ -100,7 +100,7 @@ int xioopen_stdio_bi(xiofile_t *sock) {
|
||||
return -1;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
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.
|
||||
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);
|
||||
|
||||
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) {
|
||||
return xioopen_stdio_bi(fd);
|
||||
return xioopen_stdio_bi(xfd);
|
||||
}
|
||||
|
||||
Notice2("using %s for %s",
|
||||
&("stdin\0\0\0stdout"[rw<<3]),
|
||||
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.
|
||||
@ -146,6 +149,9 @@ static int xioopen_stdfd(int argc, const char *argv[], struct opt *opts, int xio
|
||||
Notice2("using %s for %s",
|
||||
&("stdin\0\0\0stdout\0\0stderr"[fd<<3]),
|
||||
ddirection[rw]);
|
||||
return xioopen_fd(opts, rw, xfd, fd, -1, dummy2, dummy3);
|
||||
return xioopen_fd(opts, rw, xfd,
|
||||
XIOWITHRD(rw)?fd:-1,
|
||||
XIOWITHWR(rw)?fd:-1,
|
||||
dummy2, dummy3);
|
||||
}
|
||||
#endif /* WITH_STDIO */
|
||||
|
30
xio-system.c
30
xio-system.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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. */
|
||||
xiofile_t *fd,
|
||||
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[] = {
|
||||
(union xioaddr_desc *)&xioendpoint_system1,
|
||||
(union xioaddr_desc *)&xiointer_system1_2rw,
|
||||
(union xioaddr_desc *)&xiointer_system1_2ro,
|
||||
(union xioaddr_desc *)&xiointer_system1_2wo,
|
||||
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,
|
||||
int xioflags, /* XIO_RDONLY etc. */
|
||||
xiofile_t *fd,
|
||||
unsigned groups,
|
||||
int dummy1, int dummy2, int dummy3
|
||||
int inter, int form, int dummy3
|
||||
) {
|
||||
int status;
|
||||
char *path = NULL;
|
||||
@ -39,7 +59,7 @@ static int xioopen_system(int argc, const char *argv[], struct opt *opts,
|
||||
int result;
|
||||
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) { /* child */
|
||||
int numleft;
|
||||
|
@ -1,10 +1,11 @@
|
||||
/* 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 */
|
||||
|
||||
#ifndef __xio_system_h_included
|
||||
#define __xio_system_h_included 1
|
||||
|
||||
extern const union xioaddr_desc *xioaddrs_system[];
|
||||
extern const union xioaddr_desc *xioaddrs_system1[];
|
||||
|
||||
#endif /* !defined(__xio_system_h_included) */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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));
|
||||
}
|
||||
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),
|
||||
serveraddr, ntohs(us->ip4.sin_port),
|
||||
xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p'));
|
||||
request_init(&ri, RQ_FILE, xfd->fd1,
|
||||
request_init(&ri, RQ_FILE, xfd->rfd,
|
||||
RQ_CLIENT_SIN, them,
|
||||
RQ_SERVER_SIN, &us->soa,
|
||||
RQ_DAEMON, xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p'), 0);
|
||||
|
26
xio-test.c
26
xio-test.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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,
|
||||
int dummy3);
|
||||
|
||||
static const struct xioaddr_inter_desc xiointer_test0ro = { XIOADDR_PROT, "test", 0, XIOBIT_RDONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_test, 0, 0, 0, XIOBIT_WRONLY HELP("") };
|
||||
static const struct xioaddr_inter_desc xiointer_test0wo = { XIOADDR_PROT, "test", 0, XIOBIT_WRONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_test, 0, 0, 0, XIOBIT_RDONLY HELP("") };
|
||||
static const struct xioaddr_inter_desc xiointer_test0rw = { XIOADDR_PROT, "test", 0, XIOBIT_RDWR, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_test, 0, 0, 0, XIOBIT_RDWR HELP("") };
|
||||
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_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_UNSPEC, XIOCLOSE_UNSPEC, xioopen_test, 0, 0, 0, XIOBIT_RDWR HELP("") };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_test[] = {
|
||||
(union xioaddr_desc *)&xiointer_test0ro,
|
||||
@ -59,14 +59,14 @@ static int xioopen_test(int argc, const char *argv[], struct opt *opts,
|
||||
int result;
|
||||
|
||||
assert(argc == 1);
|
||||
assert(!(xfd->fd1 < 0 && xfd->fd2 < 0));
|
||||
assert(!(xfd->rfd < 0 && xfd->wfd < 0)); /*!!!*/
|
||||
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
|
||||
Notice("opening TEST");
|
||||
xfd->dtype = XIODATA_TEST;
|
||||
applyopts(xfd->fd1, opts, PH_ALL);
|
||||
applyopts(xfd->rfd, opts, PH_ALL);
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
return result;
|
||||
return 0;
|
||||
@ -80,14 +80,14 @@ static int xioopen_testuni(int argc, const char *argv[], struct opt *opts,
|
||||
int result;
|
||||
|
||||
assert(argc == 1);
|
||||
assert(!(xfd->fd1 < 0 && xfd->fd2 < 0));
|
||||
assert(!(xfd->rfd < 0 && xfd->wfd < 0)); /*!!!*/
|
||||
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
|
||||
Notice("opening TESTUNI");
|
||||
xfd->dtype = XIODATA_TESTUNI;
|
||||
applyopts(xfd->fd1, opts, PH_ALL);
|
||||
applyopts(xfd->rfd, opts, PH_ALL);
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
return result;
|
||||
return 0;
|
||||
@ -101,21 +101,21 @@ static int xioopen_testrev(int argc, const char *argv[], struct opt *opts,
|
||||
int result;
|
||||
|
||||
assert(argc == 1);
|
||||
assert(!(xfd->fd1 < 0 && xfd->fd2 < 0));
|
||||
assert(!(xfd->rfd < 0 && xfd->wfd < 0)); /*!!!*/
|
||||
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
|
||||
Notice("opening TESTREV");
|
||||
xfd->dtype = XIODATA_TESTREV;
|
||||
applyopts(xfd->fd1, opts, PH_ALL);
|
||||
applyopts(xfd->rfd, opts, PH_ALL);
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t xioread_test(struct single *sfd, void *buff, size_t bufsiz) {
|
||||
int fd = sfd->fd1;
|
||||
int fd = sfd->rfd;
|
||||
ssize_t bytes;
|
||||
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) {
|
||||
int fd = ((sfd->fdtype==FDTYPE_DOUBLE)?sfd->fd2:sfd->fd1);
|
||||
int fd = sfd->wfd;
|
||||
void *buff1;
|
||||
ssize_t writt;
|
||||
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) {
|
||||
int fd = ((sfd->fdtype==FDTYPE_DOUBLE)?sfd->fd2:sfd->fd1);
|
||||
int fd = sfd->wfd;
|
||||
void *buff1;
|
||||
ssize_t writt;
|
||||
int _errno;
|
||||
|
19
xio-tun.c
19
xio-tun.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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");
|
||||
if ((result = _xioopen_open(tundevice, rw, opts)) < 0)
|
||||
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 */
|
||||
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",
|
||||
xfd->stream.fd1, ifr.ifr_name, strerror(errno));
|
||||
Close(xfd->stream.fd1);
|
||||
xfd->stream.rfd, ifr.ifr_name, strerror(errno));
|
||||
Close(xfd->stream.rfd);
|
||||
}
|
||||
|
||||
/*===================== 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 */
|
||||
if ((sockfd = Socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
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 ------------*/
|
||||
@ -201,10 +202,10 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
|
||||
#if LATER
|
||||
applyopts_named(tundevice, opts, PH_FD);
|
||||
#endif
|
||||
applyopts(xfd->stream.fd1, opts, PH_FD);
|
||||
applyopts_cloexec(xfd->stream.fd1, opts);
|
||||
applyopts(xfd->stream.rfd, opts, PH_FD);
|
||||
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)
|
||||
return result;
|
||||
|
71
xio-udp.c
71
xio-udp.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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,
|
||||
unsigned groups, int pf, int ipproto,
|
||||
int protname) {
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
const char *portname = argv[1];
|
||||
union sockaddr_union us;
|
||||
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;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
fd->stream.fdtype = FDTYPE_SINGLE;
|
||||
|
||||
uslen = socket_init(pf, &us);
|
||||
retropt_bind(opts, pf, socktype, IPPROTO_UDP,
|
||||
(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 *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;
|
||||
}
|
||||
/*0 Info4("socket(%d, %d, %d) -> %d", pf, socktype, ipproto, fd->stream.fd);*/
|
||||
applyopts(fd->stream.fd1, opts, PH_PASTSOCKET);
|
||||
if (Setsockopt(fd->stream.fd1, opt_so_reuseaddr.major,
|
||||
applyopts(fd->stream.rfd, opts, PH_PASTSOCKET);
|
||||
if (Setsockopt(fd->stream.rfd, opt_so_reuseaddr.major,
|
||||
opt_so_reuseaddr.minor, &one, sizeof(one)) < 0) {
|
||||
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));
|
||||
}
|
||||
applyopts_cloexec(fd->stream.fd1, opts);
|
||||
applyopts(fd->stream.fd1, opts, PH_PREBIND);
|
||||
applyopts(fd->stream.fd1, opts, PH_BIND);
|
||||
if (Bind(fd->stream.fd1, &us.soa, uslen) < 0) {
|
||||
Error4("bind(%d, {%s}, "F_Zd"): %s", fd->stream.fd1,
|
||||
applyopts_cloexec(fd->stream.rfd, opts);
|
||||
applyopts(fd->stream.rfd, opts, PH_PREBIND);
|
||||
applyopts(fd->stream.rfd, opts, PH_BIND);
|
||||
if (Bind(fd->stream.rfd, &us.soa, uslen) < 0) {
|
||||
Error4("bind(%d, {%s}, "F_Zd"): %s", fd->stream.rfd,
|
||||
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)),
|
||||
uslen, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
/* under some circumstances bind() fills sockaddr with interesting info. */
|
||||
if (Getsockname(fd->stream.fd1, &us.soa, &uslen) < 0) {
|
||||
if (Getsockname(fd->stream.rfd, &us.soa, &uslen) < 0) {
|
||||
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",
|
||||
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)));
|
||||
readfd.fd = fd->stream.fd1;
|
||||
readfd.fd = fd->stream.rfd;
|
||||
readfd.events = POLLIN|POLLERR;
|
||||
while (xiopoll(&readfd, 1, NULL) < 0) {
|
||||
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);
|
||||
do {
|
||||
result = Recvfrom(fd->stream.fd1, buff1, 1, MSG_PEEK,
|
||||
result = Recvfrom(fd->stream.rfd, buff1, 1, MSG_PEEK,
|
||||
&them->soa, &themlen);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
if (result < 0) {
|
||||
Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_Zu"}): %s",
|
||||
fd->stream.fd1, buff1,
|
||||
fd->stream.rfd, buff1,
|
||||
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
|
||||
themlen, strerror(errno));
|
||||
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) {
|
||||
/* drop packet */
|
||||
char buff[512];
|
||||
Recv(fd->stream.fd1, buff, sizeof(buff), 0); /* drop packet */
|
||||
Close(fd->stream.fd1);
|
||||
Recv(fd->stream.rfd, buff, sizeof(buff), 0); /* drop packet */
|
||||
Close(fd->stream.rfd);
|
||||
continue;
|
||||
}
|
||||
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() */
|
||||
/* when we dont close this we get awkward behaviour on Linux 2.4:
|
||||
recvfrom gives 0 bytes with invalid socket address */
|
||||
if (Close(fd->stream.fd1) < 0) {
|
||||
Info2("close(%d): %s", fd->stream.fd1, strerror(errno));
|
||||
if (Close(fd->stream.rfd) < 0) {
|
||||
Info2("close(%d): %s", fd->stream.rfd, strerror(errno));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
applyopts(fd->stream.fd1, opts, PH_CONNECT);
|
||||
if ((result = Connect(fd->stream.fd1, &them->soa, themlen)) < 0) {
|
||||
applyopts(fd->stream.rfd, opts, PH_CONNECT);
|
||||
if ((result = Connect(fd->stream.rfd, &them->soa, themlen)) < 0) {
|
||||
Error4("connect(%d, {%s}, "F_Zd"): %s",
|
||||
fd->stream.fd1,
|
||||
fd->stream.rfd,
|
||||
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
|
||||
themlen, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
/* 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",
|
||||
fd->stream.fd1, &us.soa, uslen, strerror(errno));
|
||||
fd->stream.rfd, &us.soa, uslen, strerror(errno));
|
||||
}
|
||||
xiosetsockaddrenv("SOCK", &us, uslen, IPPROTO_UDP);
|
||||
xiosetsockaddrenv("PEER", them, themlen, IPPROTO_UDP);
|
||||
|
||||
applyopts_fchown(fd->stream.fd1, opts);
|
||||
applyopts(fd->stream.fd1, opts, PH_LATE);
|
||||
applyopts_fchown(fd->stream.rfd, opts);
|
||||
applyopts(fd->stream.rfd, opts, PH_LATE);
|
||||
|
||||
if ((result = _xio_openlate(&fd->stream, opts)) < 0)
|
||||
return result;
|
||||
|
||||
if (XIOWITHWR(rw)) fd->stream.wfd = fd->stream.rfd;
|
||||
if (!XIOWITHRD(rw)) fd->stream.rfd = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -338,6 +340,7 @@ int _xioopen_udp_sendto(const char *hostname, const char *servname,
|
||||
int xioflags, xiofile_t *xxfd, unsigned groups,
|
||||
int pf, int socktype, int ipproto) {
|
||||
xiosingle_t *xfd = &xxfd->stream;
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
union sockaddr_union us;
|
||||
socklen_t uslen;
|
||||
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;
|
||||
return _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||
if ((result =
|
||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
26
xio-unix.c
26
xio-unix.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* 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 */
|
||||
const char *name;
|
||||
struct single *xfd = &xxfd->stream;
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
int pf = PF_UNIX;
|
||||
int socktype = SOCK_STREAM;
|
||||
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) {
|
||||
return result;
|
||||
}
|
||||
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
|
||||
if (!XIOWITHRD(rw)) xfd->rfd = -1;
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0) {
|
||||
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) {
|
||||
/* we expect the form: filename */
|
||||
const char *name;
|
||||
xiosingle_t *xfd = &xxfd->stream;
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
int pf = PF_UNIX;
|
||||
int socktype = SOCK_DGRAM;
|
||||
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 needbind = false;
|
||||
bool opt_unlink_close = false;
|
||||
int result;
|
||||
|
||||
if (argc != 2) {
|
||||
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);
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
|
||||
return
|
||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||
opts, xioflags, xfd, groups,
|
||||
pf, socktype, protocol);
|
||||
if ((result =
|
||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||
opts, xioflags, xfd, groups,
|
||||
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
|
||||
_xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
|
||||
int abstract, struct opt *opts, const char *name) {
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
int pf = PF_UNIX;
|
||||
int socktype = 0; /* to be determined by server socket type */
|
||||
int protocol = 0;
|
||||
@ -537,6 +551,8 @@ _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
|
||||
xfd->dtype = XIODATA_RECVFROM;
|
||||
}
|
||||
}
|
||||
if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
|
||||
if (!XIOWITHRD(rw)) xfd->rfd = -1;
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0) {
|
||||
return result;
|
||||
}
|
||||
|
59
xio.h
59
xio.h
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
#ifndef __xio_h_included
|
||||
@ -59,6 +59,9 @@ struct opt;
|
||||
/* reverse the direction pattern */
|
||||
#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 */
|
||||
#define XIODATA_READMASK 0xf000 /* mask for basic r/w method */
|
||||
#define XIOREAD_STREAM 0x1000 /* read() (default) */
|
||||
@ -125,7 +128,8 @@ struct opt;
|
||||
#define XIOSHUT_CLOSE (XIOSHUTRD_CLOSE|XIOSHUTWR_CLOSE)
|
||||
#define XIOSHUT_DOWN (XIOSHUTRD_DOWN|XIOSHUTWR_DOWN)
|
||||
#define XIOSHUT_KILL (XIOSHUTRD_KILL|XIOSHUTWR_KILL)
|
||||
#define XIOSHUT_OPENSSL 0x0100 /* specific action on openssl */
|
||||
#define 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 */
|
||||
@ -136,8 +140,8 @@ struct opt;
|
||||
#define XIOCLOSE_CLOSE_SIGTERM 0x0005 /* close fd, then send SIGTERM */
|
||||
#define XIOCLOSE_CLOSE_SIGKILL 0x0006 /* close fd, then send SIGKILL */
|
||||
#define XIOCLOSE_SLEEP_SIGTERM 0x0007 /* short sleep, then SIGTERM */
|
||||
#define XIOCLOSE_OPENSSL 0x0100
|
||||
#define XIOCLOSE_READLINE 0x0101
|
||||
#define XIOCLOSE_OPENSSL 0x0101
|
||||
#define XIOCLOSE_READLINE 0x0102
|
||||
|
||||
/* these are the values allowed for the "enum xiotag tag" flag of the "struct
|
||||
single" and "union bipipe" (xiofile_t) structures. */
|
||||
@ -150,6 +154,17 @@ enum xiotag {
|
||||
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;
|
||||
|
||||
@ -159,6 +174,16 @@ union bipipe;
|
||||
#define XIOADDR_SYS XIOADDR_ENDPOINT
|
||||
#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 {
|
||||
int tag; /* 0: endpoint addr; 1: inter addr */
|
||||
const char *defname; /* main (canonical) name of address */
|
||||
@ -217,7 +242,8 @@ union xioaddr_desc {
|
||||
} ;
|
||||
|
||||
union xioaddr_descp {
|
||||
struct xioaddr_common_desc *common_desc;
|
||||
struct xioaddr_common_desc *
|
||||
common_desc;
|
||||
int *tag; /* 0: endpoint addr; 1: inter addr */
|
||||
struct xioaddr_inter_desc *inter_desc;
|
||||
struct xioaddr_endpoint_desc *endpoint_desc;
|
||||
@ -256,6 +282,8 @@ typedef struct {
|
||||
struct timeval closwait; /* after close of x, die after seconds */
|
||||
bool lefttoright; /* first addr ro, second addr wo */
|
||||
bool righttoleft; /* first addr wo, second addr ro */
|
||||
int pipetype; /* communication (pipe) type; 0: 2 unidirectional
|
||||
socketpairs; 1: 2 pipes; 2: 1 socketpair */
|
||||
} xioopts_t;
|
||||
|
||||
/* pack the description of a lock file */
|
||||
@ -305,12 +333,8 @@ typedef struct single {
|
||||
const char *argv[MAXARGV]; /* address keyword, required args */
|
||||
struct opt *opts; /* the options of this address */
|
||||
int lineterm; /* 0..dont touch; 1..CR; 2..CRNL on extern data */
|
||||
int fd1;
|
||||
int fd2;
|
||||
enum {
|
||||
FDTYPE_SINGLE, /* only fd1 is in use, for reading and/or writing */
|
||||
FDTYPE_DOUBLE /* fd2 is in use too - for writing */
|
||||
} fdtype;
|
||||
int rfd; /* was fd1 */
|
||||
int wfd; /* was fd2 */
|
||||
pid_t subaddrpid; /* pid of subaddress (process handling next addr in
|
||||
chain) */
|
||||
int subaddrstat; /* state of subaddress process
|
||||
@ -485,8 +509,8 @@ typedef union bipipe {
|
||||
#define XIO_READABLE(s) (((s)->common.flags+1)&1)
|
||||
#define XIO_RDSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]:&(s)->stream)
|
||||
#define XIO_WRSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[1]:&(s)->stream)
|
||||
#define XIO_GETRDFD(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]->fd1:(s)->stream.fd1)
|
||||
#define _XIO_GETWRFD(s) (((s)->fdtype==FDTYPE_DOUBLE)?(s)->fd2:(s)->fd1)
|
||||
#define XIO_GETRDFD(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]->rfd:(s)->stream.rfd)
|
||||
#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_EOF(s) (XIO_RDSTREAM(s)->eof && !XIO_RDSTREAM(s)->ignoreeof)
|
||||
|
||||
@ -562,12 +586,13 @@ struct opt {
|
||||
|
||||
/* with threading, the arguments indirectly passed to xioengine() */
|
||||
struct threadarg_struct {
|
||||
int rw; /* one of XIO_RDONLY, ... */
|
||||
xiofile_t *xfd1;
|
||||
xiofile_t *xfd2;
|
||||
} ;
|
||||
|
||||
extern const char *PIPESEP;
|
||||
extern xiofile_t *sock[XIO_MAXSOCK];
|
||||
extern xiofile_t *sock[XIO_MAXSOCK]; /*!!!*/
|
||||
|
||||
/* return values of xioopensingle */
|
||||
#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 xiofile_t *xioopen(const char *args, int xioflags);
|
||||
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 xioopenhelp(FILE *of, int level);
|
||||
|
25
xioclose.c
25
xioclose.c
@ -38,8 +38,8 @@ int xioclose1(struct single *pipe) {
|
||||
sycSSL_free(pipe->para.openssl.ssl);
|
||||
pipe->para.openssl.ssl = NULL;
|
||||
}
|
||||
Close(pipe->fd1); pipe->fd1 = -1;
|
||||
Close(pipe->fd2); pipe->fd2 = -1;
|
||||
Close(pipe->rfd); pipe->rfd = -1;
|
||||
Close(pipe->wfd); pipe->wfd = -1;
|
||||
if (pipe->para.openssl.ctx) {
|
||||
sycSSL_CTX_free(pipe->para.openssl.ctx);
|
||||
pipe->para.openssl.ctx = NULL;
|
||||
@ -64,15 +64,20 @@ int xioclose1(struct single *pipe) {
|
||||
}
|
||||
/*PASSTHROUGH*/
|
||||
case XIOCLOSE_CLOSE:
|
||||
if (pipe->fd1 >= 0) {
|
||||
if (Close(pipe->fd1) < 0) {
|
||||
Info2("close(%d): %s", pipe->fd1, strerror(errno));
|
||||
if (XIOWITHRD(pipe->flags) && pipe->rfd >= 0) {
|
||||
if (Close(pipe->rfd) < 0) {
|
||||
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;
|
||||
|
||||
case XIOCLOSE_SLEEP_SIGTERM:
|
||||
Sleep(1);
|
||||
Usleep(250000);
|
||||
if (pipe->child.pid > 0) {
|
||||
if (Kill(pipe->child.pid, SIGTERM) < 0) {
|
||||
Msg2(errno==ESRCH?E_INFO:E_WARN, "kill(%d, SIGTERM): %s",
|
||||
@ -84,6 +89,10 @@ int xioclose1(struct single *pipe) {
|
||||
case XIOCLOSE_NONE:
|
||||
break;
|
||||
|
||||
case XIOCLOSE_UNSPEC:
|
||||
Warn1("xioclose(): no close action specified on 0x%x", pipe);
|
||||
break;
|
||||
|
||||
default:
|
||||
Error2("xioclose(): bad close action 0x%x on 0x%x", pipe->howtoclose, pipe);
|
||||
break;
|
||||
@ -91,9 +100,9 @@ int xioclose1(struct single *pipe) {
|
||||
|
||||
#if WITH_TERMIOS
|
||||
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",
|
||||
pipe->fd1, strerror(errno));
|
||||
pipe->rfd, strerror(errno));
|
||||
}
|
||||
}
|
||||
#endif /* WITH_TERMIOS */
|
||||
|
@ -442,7 +442,7 @@ int _socat(xiofile_t *xfd1, xiofile_t *xfd2) {
|
||||
if (XIO_RDSTREAM(sock1)->ignoreeof &&
|
||||
!XIO_RDSTREAM(sock1)->actescape && !sock1->stream.closing) {
|
||||
Debug1("socket 1 (fd %d) is at EOF, ignoring",
|
||||
XIO_RDSTREAM(sock1)->fd1); /*! */
|
||||
XIO_RDSTREAM(sock1)->rfd); /*! */
|
||||
mayrd1 = true;
|
||||
polling = 1; /* do not hook this eof fd to poll for pollintv*/
|
||||
} else {
|
||||
@ -465,7 +465,7 @@ int _socat(xiofile_t *xfd1, xiofile_t *xfd2) {
|
||||
if (XIO_RDSTREAM(sock2)->ignoreeof &&
|
||||
!XIO_RDSTREAM(sock2)->actescape && !sock2->stream.closing) {
|
||||
Debug1("socket 2 (fd %d) is at EOF, ignoring",
|
||||
XIO_RDSTREAM(sock2)->fd1);
|
||||
XIO_RDSTREAM(sock2)->rfd);
|
||||
mayrd2 = true;
|
||||
polling = 1; /* do not hook this eof fd to poll for pollintv*/
|
||||
} else {
|
||||
|
275
xioopen.c
275
xioopen.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* this is the source file of the extended open function */
|
||||
@ -64,6 +64,8 @@ const struct xioaddrname address_names[] = {
|
||||
#endif
|
||||
#if WITH_EXEC
|
||||
{ "exec", xioaddrs_exec },
|
||||
{ "exec1", xioaddrs_exec1 },
|
||||
{ "exec2", xioaddrs_exec },
|
||||
#endif
|
||||
#if WITH_FDNUM
|
||||
{ "fd", xioaddrs_fdnum },
|
||||
@ -230,6 +232,8 @@ const struct xioaddrname address_names[] = {
|
||||
#endif
|
||||
#if WITH_SYSTEM
|
||||
{ "system", xioaddrs_system },
|
||||
{ "system1", xioaddrs_system1 },
|
||||
{ "system2", xioaddrs_system },
|
||||
#endif
|
||||
#if (WITH_IP4 || WITH_IP6) && WITH_TCP
|
||||
{ "tcp", xioaddrs_tcp_connect },
|
||||
@ -347,11 +351,9 @@ int xioopen_makedual(xiofile_t *file) {
|
||||
if ((file->dual.stream[0] = (xiosingle_t *)xioallocfd()) == NULL)
|
||||
return -1;
|
||||
file->dual.stream[0]->flags = XIO_RDONLY;
|
||||
file->dual.stream[0]->fdtype = FDTYPE_SINGLE;
|
||||
if ((file->dual.stream[1] = (xiosingle_t *)xioallocfd()) == NULL)
|
||||
return -1;
|
||||
file->dual.stream[1]->flags = XIO_WRONLY;
|
||||
file->dual.stream[1]->fdtype = FDTYPE_SINGLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -376,9 +378,8 @@ xiofile_t *xioallocfd(void) {
|
||||
/* fd->common.ignoreeof = false; */
|
||||
/* fd->common.eof = 0; */
|
||||
|
||||
fd->stream.fd1 = -1;
|
||||
fd->stream.fd2 = -1;
|
||||
fd->stream.fdtype = FDTYPE_SINGLE;
|
||||
fd->stream.rfd = -1;
|
||||
fd->stream.wfd = -1;
|
||||
fd->stream.dtype = XIODATA_STREAM;
|
||||
#if _WITH_SOCKET
|
||||
/* fd->stream.salen = 0; */
|
||||
@ -408,9 +409,11 @@ void xiofreefd(xiofile_t *xfd) {
|
||||
|
||||
|
||||
/* 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;
|
||||
xiosingle_t *sfdA; /* what we just parse(d) */
|
||||
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 *xfd1; /* left hand of engine */
|
||||
xiofile_t *xfd2; /* returned by sub address */
|
||||
int dirs0, dirs1, dirs2; /* the data directions for respective xfd */
|
||||
int xfd0shut;
|
||||
int xfd0close;
|
||||
int lefttoright[2];
|
||||
int righttoleft[2];
|
||||
int rw0, rw1, rw2; /* the data directions for respective xfd
|
||||
directions are sepcified as seen by transfer
|
||||
engine */
|
||||
xiofd_t left, right;
|
||||
struct threadarg_struct *thread_arg;
|
||||
/*0 pthread_t thread = 0;*/
|
||||
/*pthread_attr_t attr;*/
|
||||
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) {
|
||||
|
||||
addrs = addrs0;
|
||||
skipsp(&addrs);
|
||||
dirs0 = dirs;
|
||||
rw0 = rw;
|
||||
|
||||
/* here we do not know much: will the next sub address be inter or
|
||||
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? */
|
||||
if (!strncmp(addrs, xioparams->pipesep, strlen(xioparams->pipesep))) {
|
||||
/* yes, found dual-address operator */
|
||||
if (dirs != XIO_RDWR) {
|
||||
if (rw != XIO_RDWR) {
|
||||
Error("dual address cannot handle single direction data stream");
|
||||
}
|
||||
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
|
||||
reverseA...sfdA 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 */
|
||||
|
||||
/* calculate context parameters that are easier to handle */
|
||||
if (sfdB == NULL) {
|
||||
srchleftA = mayleftA = (1 << dirs0);
|
||||
srchleftA = mayleftA = (1 << rw0);
|
||||
srchrightA = mayrightA = (currentisendpoint ? 0 : XIOBIT_ALL);
|
||||
if (reverseA) {
|
||||
/*srchrightA = XIOBIT_REVERSE(srchleftA);*/
|
||||
srchrightA = srchleftA;
|
||||
/*srchrightA = XIOBIT_REVERSE(srchleftA); no, see what right means*/
|
||||
srchleftA = XIOBIT_ALL;
|
||||
}
|
||||
} 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)
|
||||
< 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (reverseA) { isrightA = isleftA; }
|
||||
if (reverseA) {
|
||||
int tmp;
|
||||
tmp = isleftA; isrightA = isleftA; isleftA = tmp;
|
||||
}
|
||||
|
||||
if (sfdB != NULL) {
|
||||
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) */
|
||||
Error("conflict in data directions");/*!!*/
|
||||
}
|
||||
dirs1 = ((isrightA+1) | (isleftB+1)) - 1;
|
||||
rw1 = ((isrightA+1) | (isleftB+1)) - 1;
|
||||
} 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;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* if we found the endpoint address we are almost finished here */
|
||||
|
||||
if (currentisendpoint) {
|
||||
if (sfdB != NULL) {
|
||||
if ((xfd0 = xioallocfd()) == NULL) {
|
||||
@ -587,7 +594,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
|
||||
xfd0 = (xiofile_t *)sfdA;
|
||||
}
|
||||
/* 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);
|
||||
return NULL;
|
||||
}
|
||||
@ -599,7 +606,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
|
||||
/* recursively open the following addresses of chain */
|
||||
/* loop over retries if appropriate */
|
||||
do {
|
||||
xfd2 = socat_open(addrs, dirs2, flags);
|
||||
xfd2 = socat_open(addrs, rw2, flags);
|
||||
if (xfd2 != NULL) {
|
||||
break; /* succeeded */
|
||||
}
|
||||
@ -615,13 +622,14 @@ 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
|
||||
*/
|
||||
/* 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?
|
||||
consider chain: addr1|addr2
|
||||
with no reverse address, this will run like:
|
||||
_socat(<upstream>,addr1) --- _socat(-, addr2)
|
||||
_socat(???, xfd0) --- _socat(xfd1,xfd2)
|
||||
_socat(???, xfd0) --- _socat(xfd1,xfd2)
|
||||
xfd0 will be opened in this routine
|
||||
xfd1 will be assembled now, just using FDs
|
||||
xfd2 comes from recursive open call
|
||||
@ -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
|
||||
(xfd0-xfd1) */
|
||||
if (1) {
|
||||
int sv[2];
|
||||
if (Socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) {
|
||||
Error2("socketpair(PF_UNIX, PF_STREAM, 0, %s): %s",
|
||||
sv, strerror(errno));
|
||||
{
|
||||
switch (xioopts.pipetype) {
|
||||
case XIOCOMM_SOCKETPAIR:
|
||||
case XIOCOMM_SOCKETPAIRS:
|
||||
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 */
|
||||
|
||||
if (sfdB != NULL && reverseA == reverseB) {
|
||||
/* dual address, differing orientation (B is impl.reverse) */
|
||||
/* dual implies (dirs0==dirs1==XIO_RDWR) */
|
||||
/* dual implies (rw0==rw1==XIO_RDWR) */
|
||||
if (!reverseA) {
|
||||
/* A is not reverse, but B */
|
||||
char addr[15];
|
||||
@ -675,7 +692,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
|
||||
xfd0 = xioallocfd();
|
||||
xioopen_makedual(xfd0);
|
||||
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] =
|
||||
(xiosingle_t *)socat_open(addr, XIO_WRONLY, 0))
|
||||
== NULL) {
|
||||
@ -686,7 +703,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
|
||||
xfd1 = xioallocfd();
|
||||
xioopen_makedual(xfd1);
|
||||
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] =
|
||||
(xiosingle_t *)socat_open(addr, XIO_RDONLY, 0))
|
||||
== NULL) {
|
||||
@ -700,7 +717,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
|
||||
xfd0 = xioallocfd();
|
||||
xioopen_makedual(xfd0);
|
||||
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] =
|
||||
(xiosingle_t *)socat_open(addr, XIO_RDONLY, 0))
|
||||
== NULL) {
|
||||
@ -710,7 +727,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
|
||||
xfd1 = xioallocfd();
|
||||
xioopen_makedual(xfd1);
|
||||
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] =
|
||||
(xiosingle_t *)socat_open(addr, XIO_RDONLY, 0))
|
||||
== NULL) {
|
||||
@ -718,10 +735,11 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
xfd0->dual.stream[0]->fd1 = lefttoright[1];
|
||||
xfd0->dual.stream[1]->fd1 = righttoleft[0];
|
||||
xfd1->dual.stream[0]->fd1 = righttoleft[1];
|
||||
xfd1->dual.stream[1]->fd1 = lefttoright[0];
|
||||
xfd0->dual.stream[0]->rfd = left.rfd;
|
||||
xfd0->dual.stream[1]->wfd = left.wfd;
|
||||
xfd1->dual.stream[0]->rfd = right.rfd;
|
||||
xfd1->dual.stream[1]->wfd = right.wfd;
|
||||
|
||||
} else {
|
||||
/* either dual with equal directions, or non-dual */
|
||||
xiofile_t *tfd; /* temp xfd */
|
||||
@ -741,86 +759,123 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
|
||||
if (!reverseA) {
|
||||
/* forward */
|
||||
xfd0 = tfd;
|
||||
if (dirs1 == XIO_RDWR) {
|
||||
sprintf(addr, "FD:%u:%u", righttoleft[1], lefttoright[0]);
|
||||
} else if (dirs1 == XIO_RDONLY) {
|
||||
sprintf(addr, "FD:%u", lefttoright[0]);
|
||||
if (rw1 == XIO_RDWR) {
|
||||
sprintf(addr, "FD:%u:%u", /*0 righttoleft[1]*/right.wfd, /*0 lefttoright[0]*/right.rfd);
|
||||
} else if (rw1 == XIO_RDONLY) {
|
||||
sprintf(addr, "FD:%u", /*0 lefttoright[0]*/right.rfd);
|
||||
} 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);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/* reverse */
|
||||
xfd1 = tfd;
|
||||
if (dirs0 == XIO_RDWR) {
|
||||
sprintf(addr, "FD:%u:%u", lefttoright[1], righttoleft[0]);
|
||||
} else if (dirs0 == XIO_RDONLY) {
|
||||
sprintf(addr, "FD:%u", righttoleft[0]);
|
||||
if (rw0 == XIO_RDWR) {
|
||||
sprintf(addr, "FD:%u:%u", /*0 lefttoright[1]*/left.wfd, /*0 righttoleft[0]*/left.rfd);
|
||||
} else if (rw0 == XIO_RDONLY) {
|
||||
sprintf(addr, "FD:%u", /*0 righttoleft[0]*/left.rfd);
|
||||
} 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);
|
||||
return NULL;
|
||||
}
|
||||
/* address type FD keeps the FDs open per default, but ... */
|
||||
}
|
||||
if (xfd0->tag == XIO_TAG_DUAL) {
|
||||
xfd0->dual.stream[0]->fd1 = lefttoright[1];
|
||||
xfd0->dual.stream[1]->fd1 = righttoleft[0];
|
||||
xfd0->dual.stream[0]->rfd = /*0 righttoleft[0]*/left.rfd;
|
||||
xfd0->dual.stream[1]->wfd = /*0 lefttoright[1]*/left.wfd;
|
||||
} else {
|
||||
xfd0->stream.fd1 = righttoleft[0];
|
||||
xfd0->stream.fd2 = lefttoright[1];
|
||||
xfd0->stream.rfd = /*0 righttoleft[0]*/left.rfd;
|
||||
xfd0->stream.wfd = /*0 lefttoright[1]*/left.wfd;
|
||||
}
|
||||
if (xfd1->tag == XIO_TAG_DUAL) {
|
||||
xfd1->dual.stream[0]->fd1 = righttoleft[1];
|
||||
xfd1->dual.stream[1]->fd1 = lefttoright[0];
|
||||
xfd1->dual.stream[0]->rfd = /*0 righttoleft[0]*/left.rfd;
|
||||
xfd1->dual.stream[1]->rfd = /*0 lefttoright[1]*/left.wfd;
|
||||
} else {
|
||||
xfd1->stream.fd1 = lefttoright[0];
|
||||
xfd1->stream.fd2 = righttoleft[1];
|
||||
xfd1->stream.rfd = /*0 lefttoright[0]*/right.rfd;
|
||||
xfd1->stream.wfd = /*0 righttoleft[1]*/right.wfd;
|
||||
}
|
||||
}
|
||||
|
||||
/* address type FD keeps the FDs open per default, but ... */
|
||||
if (xfd0->tag == XIO_TAG_DUAL) {
|
||||
xfd0->dual.stream[0]->howtoshut = xfd0shut;
|
||||
xfd0->dual.stream[0]->howtoclose = xfd0close;
|
||||
xfd0->dual.stream[1]->howtoshut = xfd0shut;
|
||||
xfd0->dual.stream[1]->howtoclose = xfd0close;
|
||||
xfd0->dual.stream[0]->howtoshut = left.howtoshut;
|
||||
xfd0->dual.stream[0]->howtoclose = left.howtoclose;
|
||||
xfd0->dual.stream[0]->dtype = left.dtype;
|
||||
xfd0->dual.stream[1]->howtoshut = right.howtoshut;
|
||||
xfd0->dual.stream[1]->howtoclose = right.howtoclose;
|
||||
xfd0->dual.stream[1]->dtype = right.dtype;
|
||||
} else {
|
||||
xfd0->stream.howtoshut = xfd0shut;
|
||||
xfd0->stream.howtoclose = xfd0close;
|
||||
xfd0->stream.howtoshut = left.howtoshut;
|
||||
xfd0->stream.howtoclose = left.howtoclose;
|
||||
xfd0->stream.dtype = left.dtype;
|
||||
}
|
||||
if (xfd1->tag == XIO_TAG_DUAL) {
|
||||
xfd1->dual.stream[0]->howtoshut = xfd0shut;
|
||||
xfd1->dual.stream[0]->howtoclose = xfd0close;
|
||||
xfd1->dual.stream[1]->howtoshut = xfd0shut;
|
||||
xfd1->dual.stream[1]->howtoclose = xfd0close;
|
||||
xfd1->dual.stream[0]->howtoshut = left.howtoshut;
|
||||
xfd1->dual.stream[0]->howtoclose = left.howtoclose;
|
||||
xfd1->dual.stream[0]->dtype = left.dtype;
|
||||
xfd1->dual.stream[1]->howtoshut = right.howtoshut;
|
||||
xfd1->dual.stream[1]->howtoclose = right.howtoclose;
|
||||
xfd1->dual.stream[1]->dtype = right.dtype;
|
||||
} else {
|
||||
xfd1->stream.howtoshut = xfd0shut;
|
||||
xfd1->stream.howtoclose = xfd0close;
|
||||
xfd1->stream.howtoshut = right.howtoshut;
|
||||
xfd1->stream.howtoclose = right.howtoclose;
|
||||
xfd1->stream.dtype = right.dtype;
|
||||
}
|
||||
|
||||
/* here xfd2 is valid and ready for transfer;
|
||||
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) {
|
||||
/*! free something */
|
||||
xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2);
|
||||
return NULL;
|
||||
}
|
||||
thread_arg->rw = (reverseA ? rw1 : rw0);
|
||||
thread_arg->xfd1 = xfd1;
|
||||
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 =
|
||||
Pthread_create(&xfd0->stream.subthread, NULL,
|
||||
(reverseA||(sfdB!=NULL)&&!reverseB)?xioopenleftthenengine:xioengine,
|
||||
thread_arg))
|
||||
!= 0) {
|
||||
Error4("pthread_create(%p, {}, xioengine, {%p,%p}): %s",
|
||||
&xfd0->stream.subthread, thread_arg->xfd1, thread_arg->xfd2,
|
||||
Error3("pthread_create(%p, {}, xioengine, %p): %s",
|
||||
&xfd0->stream.subthread, thread_arg,
|
||||
strerror(_errno));
|
||||
xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2);
|
||||
free(thread_arg); return NULL;
|
||||
@ -830,7 +885,7 @@ xiofile_t *socat_open(const char *addrs0, int dirs, int flags) {
|
||||
xfd2 = NULL;
|
||||
|
||||
/* open protocol part */
|
||||
if (xioopen_inter_dual(xfd0, dirs|flags)
|
||||
if (xioopen_inter_dual(xfd0, rw|flags)
|
||||
< 0) {
|
||||
/*! close sub chain */
|
||||
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) {
|
||||
struct threadarg_struct *thread_arg = thread_void;
|
||||
int rw = thread_arg->rw;
|
||||
xiofile_t *xfd1 = thread_arg->xfd1;
|
||||
xiofile_t *xfd2 = thread_arg->xfd2;
|
||||
|
||||
/*! design a function with better interface */
|
||||
if (xioopen_inter_dual(xfd1, XIO_RDWR|XIO_MAYCONVERT) < 0) {
|
||||
if (xioopen_inter_dual(xfd1, rw|XIO_MAYCONVERT|XIO_MAYCHILD) < 0) {
|
||||
xioclose(xfd2);
|
||||
xiofreefd(xfd1);
|
||||
xiofreefd(xfd2);
|
||||
@ -1120,7 +1176,7 @@ static int
|
||||
tag = (mayright ? XIOADDR_INTER : XIOADDR_ENDPOINT);
|
||||
|
||||
/* 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,
|
||||
tag, sfd->argc-1, mayleft, mayright);
|
||||
while ((*addrdescs) != NULL) {
|
||||
@ -1134,9 +1190,13 @@ static int
|
||||
}
|
||||
|
||||
if (addrdescs[0] == NULL) {
|
||||
Error3("address \"%s...\" in %s context and with %d parameter(s) is not defined",
|
||||
sfd->argv[0], tag==XIOADDR_ENDPOINT?"endpoint":"intermediate",
|
||||
sfd->argc-1);
|
||||
if (tag == XIOADDR_ENDPOINT) {
|
||||
Error3("address \"%s...\" in endpoint context, leftdirs=%d, with %d parameter(s) is not available",
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1154,9 +1214,19 @@ static int
|
||||
}
|
||||
sfd->tag = (*isleft + 1);
|
||||
sfd->addrdesc = addrdescs[0];
|
||||
sfd->howtoshut = addrdescs[0]->common_desc.howtoshut;
|
||||
sfd->howtoclose = addrdescs[0]->common_desc.howtoclose;
|
||||
if (addrdescs[0]->common_desc.howtoshut != XIOSHUT_UNSPEC)
|
||||
sfd->howtoshut = addrdescs[0]->common_desc.howtoshut;
|
||||
if (addrdescs[0]->common_desc.howtoclose != XIOCLOSE_UNSPEC)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1170,17 +1240,10 @@ static int
|
||||
|
||||
if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) {
|
||||
xfd->tag = XIO_TAG_RDONLY;
|
||||
xfd->stream.fdtype = FDTYPE_SINGLE;
|
||||
} else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) {
|
||||
xfd->tag = XIO_TAG_WRONLY;
|
||||
xfd->stream.fdtype = FDTYPE_SINGLE;
|
||||
} else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) {
|
||||
xfd->tag = XIO_TAG_RDWR;
|
||||
if (xfd->stream.fd2 >= 0) {
|
||||
xfd->stream.fdtype = FDTYPE_DOUBLE;
|
||||
} else {
|
||||
xfd->stream.fdtype = FDTYPE_SINGLE;
|
||||
}
|
||||
} else {
|
||||
Error1("invalid mode for address \"%s\"", xfd->stream.argv[0]);
|
||||
}
|
||||
@ -1201,10 +1264,8 @@ static int
|
||||
addrdesc = &xfd->stream.addrdesc->endpoint_desc;
|
||||
if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) {
|
||||
xfd->tag = XIO_TAG_RDONLY;
|
||||
xfd->stream.fdtype = FDTYPE_SINGLE;
|
||||
} else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) {
|
||||
xfd->tag = XIO_TAG_WRONLY;
|
||||
xfd->stream.fdtype = FDTYPE_SINGLE;
|
||||
} else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) {
|
||||
xfd->tag = XIO_TAG_RDWR;
|
||||
} else {
|
||||
|
48
xioopts.c
48
xioopts.c
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
/* this file contains the source for address options handling */
|
||||
@ -296,6 +296,7 @@ const struct optname optionnames[] = {
|
||||
IF_TERMIOS("clocal", &opt_clocal)
|
||||
IF_ANY ("cloexec", &opt_cloexec)
|
||||
IF_ANY ("close", &opt_end_close)
|
||||
IF_EXEC ("commtype", &opt_commtype)
|
||||
#if WITH_EXT2 && defined(EXT2_COMPR_FL)
|
||||
IF_ANY ("compr", &opt_ext2_compr)
|
||||
#endif
|
||||
@ -497,8 +498,8 @@ const struct optname optionnames[] = {
|
||||
IF_ANY ("f-setlkw", &opt_f_setlkw_wr)
|
||||
IF_ANY ("f-setlkw-rd", &opt_f_setlkw_rd)
|
||||
IF_ANY ("f-setlkw-wr", &opt_f_setlkw_wr)
|
||||
IF_EXEC ("fdin", &opt_fdin)
|
||||
IF_EXEC ("fdout", &opt_fdout)
|
||||
IF_EXEC ("fdin", &opt_leftinfd)
|
||||
IF_EXEC ("fdout", &opt_leftoutfd)
|
||||
#ifdef FFDLY
|
||||
# ifdef FF0
|
||||
IF_TERMIOS("ff0", &opt_ff0)
|
||||
@ -805,6 +806,10 @@ const struct optname optionnames[] = {
|
||||
#ifdef O_LARGEFILE
|
||||
IF_OPEN ("largefile", &opt_o_largefile)
|
||||
#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_IPAPP ("libwrap", &opt_tcpwrappers)
|
||||
#endif
|
||||
@ -1195,6 +1200,12 @@ const struct optname optionnames[] = {
|
||||
#ifdef TCP_RFC1323
|
||||
IF_TCP ("rfc1323", &opt_tcp_rfc1323)
|
||||
#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
|
||||
IF_IP ("routeralert", &opt_ip_router_alert)
|
||||
#endif
|
||||
@ -1272,6 +1283,8 @@ const struct optname optionnames[] = {
|
||||
IF_SOCKET ("setsockopt-string", &opt_setsockopt_string)
|
||||
IF_ANY ("setuid", &opt_setuid)
|
||||
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 WITH_EXEC || WITH_SYSTEM
|
||||
IF_ANY ("sid", &opt_setsid)
|
||||
@ -3964,10 +3977,10 @@ mc:addr
|
||||
#endif
|
||||
|
||||
#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) {
|
||||
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_address.s_addr,
|
||||
ip4_mreqn.mreqn.imr_ifindex,
|
||||
@ -4017,10 +4030,10 @@ mc:addr
|
||||
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) {
|
||||
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,
|
||||
sizeof(ip6_mreq),
|
||||
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
|
||||
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 result;
|
||||
|
||||
if (xfd->rfd >= 0) {
|
||||
fd = xfd->rfd;
|
||||
} else {
|
||||
fd = xfd->wfd;
|
||||
}
|
||||
|
||||
_xioopen_setdelayeduser();
|
||||
|
||||
if ((result = applyopts(fd->fd1, opts, PH_LATE)) < 0) {
|
||||
if ((result = applyopts(fd, opts, PH_LATE)) < 0) {
|
||||
return result;
|
||||
}
|
||||
#if 0 /*! need to copy opts before previous statement! */
|
||||
if (fd->fdtype == FDTYPE_DOUBLE) {
|
||||
if ((result = applyopts(fd->fd2, opts, PH_LATE)) < 0) {
|
||||
if (xfd->fdtype == FDTYPE_DOUBLE) {
|
||||
if ((result = applyopts(fd, opts, PH_LATE)) < 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if ((result = applyopts_single(fd, opts, PH_LATE)) < 0) {
|
||||
if ((result = applyopts_single(xfd, opts, PH_LATE)) < 0) {
|
||||
return result;
|
||||
}
|
||||
if ((result = applyopts(fd->fd1, opts, PH_LATE2)) < 0) {
|
||||
if ((result = applyopts(fd, opts, PH_LATE2)) < 0) {
|
||||
return result;
|
||||
}
|
||||
/*! need to apply to fd2 too! */
|
||||
/*! need to apply to wfd too! */
|
||||
|
||||
if ((numleft = leftopts(opts)) > 0) {
|
||||
showleft(opts);
|
||||
|
13
xioopts.h
13
xioopts.h
@ -1,5 +1,5 @@
|
||||
/* 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 */
|
||||
|
||||
#ifndef __xioopts_h_included
|
||||
@ -235,6 +235,7 @@ enum e_optcode {
|
||||
/*OPT_CIBAUD,*/ /* termios.c_cflag */
|
||||
OPT_CLOCAL, /* termios.c_cflag */
|
||||
OPT_CLOEXEC,
|
||||
OPT_COMMTYPE, /* exec/system communication type */
|
||||
OPT_CONNECT_TIMEOUT, /* socket connect */
|
||||
OPT_COOL_WRITE,
|
||||
OPT_CR, /* customized */
|
||||
@ -288,8 +289,9 @@ enum e_optcode {
|
||||
OPT_EXT2_NOTAIL,
|
||||
OPT_EXT2_DIRSYNC,
|
||||
OPT_EXT2_TOPDIR,
|
||||
OPT_FDIN,
|
||||
OPT_FDOUT,
|
||||
OPT_LEFTFD,
|
||||
OPT_LEFTINFD,
|
||||
OPT_LEFTOUTFD,
|
||||
#ifdef FFDLY
|
||||
# ifdef FF0
|
||||
OPT_FF0, /* termios.c_oflag */
|
||||
@ -573,6 +575,9 @@ enum e_optcode {
|
||||
OPT_RES_STAYOPEN, /* resolver(3) */
|
||||
OPT_RES_USEVC, /* resolver(3) */
|
||||
OPT_RETRY,
|
||||
OPT_RIGHTFD, /* inter exec, system */
|
||||
OPT_RIGHTINFD, /* inter exec, system */
|
||||
OPT_RIGHTOUTFD, /* inter exec, system */
|
||||
OPT_SANE, /* termios */
|
||||
OPT_SCTP_MAXSEG,
|
||||
OPT_SCTP_MAXSEG_LATE,
|
||||
@ -592,6 +597,8 @@ enum e_optcode {
|
||||
OPT_SETSOCKOPT_STRING,
|
||||
OPT_SETUID,
|
||||
OPT_SETUID_EARLY,
|
||||
OPT_SHUT_CLOSE,
|
||||
OPT_SHUT_DOWN,
|
||||
OPT_SHUT_NONE,
|
||||
OPT_SIGHUP,
|
||||
OPT_SIGINT,
|
||||
|
@ -32,6 +32,7 @@ xioopts_t xioopts = {
|
||||
{0,500000}, /* closwait */
|
||||
false, /* lefttoright */
|
||||
false, /* righttoleft */
|
||||
0, /* pipetype: two unidirectional socketpairs */
|
||||
} ;
|
||||
xioopts_t *xioparams = &xioopts;
|
||||
|
||||
|
@ -158,7 +158,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
||||
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
|
||||
msgh.msg_controllen = sizeof(ctrlbuff);
|
||||
#endif
|
||||
if (xiogetpacketsrc(pipe->fd1, &msgh) < 0) {
|
||||
if (xiogetpacketsrc(pipe->rfd, &msgh) < 0) {
|
||||
return -1;
|
||||
}
|
||||
do {
|
||||
@ -350,7 +350,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
||||
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
|
||||
msgh.msg_controllen = sizeof(ctrlbuff);
|
||||
#endif
|
||||
if (xiogetpacketsrc(pipe->fd1, &msgh) < 0) {
|
||||
if (xiogetpacketsrc(pipe->rfd, &msgh) < 0) {
|
||||
return -1;
|
||||
}
|
||||
xiodopacketinfo(&msgh, true, false);
|
||||
|
@ -52,6 +52,40 @@ int xioshutdown(xiofile_t *sock, int how) {
|
||||
|
||||
/* here handle special shutdown functions */
|
||||
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
|
||||
case XIOSHUT_OPENSSL:
|
||||
sycSSL_shutdown(sock->stream.para.openssl.ssl);
|
||||
@ -120,9 +154,9 @@ int xioshutdown(xiofile_t *sock, int how) {
|
||||
|
||||
case XIOREAD_STREAM:
|
||||
case XIODATA_2PIPE:
|
||||
if (Close(sock->stream.fd1) < 0) {
|
||||
if (Close(sock->stream.rfd) < 0) {
|
||||
Info2("close(%d): %s",
|
||||
sock->stream.fd1, strerror(errno));
|
||||
sock->stream.rfd, strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -132,11 +166,7 @@ int xioshutdown(xiofile_t *sock, int how) {
|
||||
/* shutdown write channel */
|
||||
int fd;
|
||||
|
||||
if (sock->stream.fdtype == FDTYPE_DOUBLE) {
|
||||
fd = sock->stream.fd2;
|
||||
} else {
|
||||
fd = sock->stream.fd1;
|
||||
}
|
||||
fd = sock->stream.wfd;
|
||||
|
||||
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",
|
||||
sock->stream.howtoshut&XIOSHUTWR_MASK);
|
||||
}
|
||||
sock->stream.wfd = -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
514
xiosocketpair.c
514
xiosocketpair.c
@ -1,14 +1,16 @@
|
||||
/* $Id$ */
|
||||
/* Copyright Gerhard Rieger 2007 */
|
||||
/* Copyright Gerhard Rieger 2007-2009 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this is the source of the internal xiosocketpair function */
|
||||
|
||||
#include "xiosysincludes.h"
|
||||
#include "sycls.h"
|
||||
#include "compat.h"
|
||||
#include "error.h"
|
||||
#include "xio.h"
|
||||
|
||||
|
||||
#if defined(HAVE_DEV_PTMX)
|
||||
# define PTMX "/dev/ptmx" /* Linux */
|
||||
#elif HAVE_DEV_PTC
|
||||
@ -17,170 +19,388 @@
|
||||
|
||||
#define MAXPTYNAMELEN 64
|
||||
|
||||
/* how: 0...socketpair; 1...pipes pair; 2...pty (master, slave)
|
||||
how==0: var args (int)domain, (int)type, (int)protocol
|
||||
how==1: no var args
|
||||
how==2: var args (int)useptmx
|
||||
returns -1 on error or 0 on success */
|
||||
int xiopty(int useptmx, int *ttyfdp, int *ptyfdp) {
|
||||
int ttyfd, ptyfd = -1;
|
||||
char ptyname[MAXPTYNAMELEN];
|
||||
struct termios termarg;
|
||||
|
||||
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];
|
||||
if (useptmx) {
|
||||
if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) {
|
||||
Warn1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620): %s",
|
||||
strerror(errno));
|
||||
/*!*/
|
||||
} else {
|
||||
;/*0 Info1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620) -> %d", ptyfd);*/
|
||||
}
|
||||
break;
|
||||
if (ptyfd >= 0) {
|
||||
char *tn = NULL;
|
||||
|
||||
case 1:
|
||||
{
|
||||
int filedes1[2], filedes2[2];
|
||||
if (Pipe(filedes1) < 0) {
|
||||
Error2("pipe(%p): %s", filedes1, strerror(errno));
|
||||
xiofreefd(xfd1); xiofreefd(xfd2);
|
||||
return -1;
|
||||
}
|
||||
if (Pipe(filedes2) < 0) {
|
||||
Error2("pipe(%p): %s", filedes2, strerror(errno));
|
||||
xiofreefd(xfd1); xiofreefd(xfd2);
|
||||
Close(filedes1[0]); Close(filedes1[1]);
|
||||
return -1;
|
||||
}
|
||||
xfd1->stream.fd1 = filedes1[0];
|
||||
xfd1->stream.fd2 = filedes2[1];
|
||||
xfd1->stream.fdtype = FDTYPE_DOUBLE;
|
||||
xfd1->stream.dtype = XIODATA_2PIPE;
|
||||
xfd2->stream.fd1 = filedes2[0];
|
||||
xfd2->stream.fd2 = filedes1[1];
|
||||
xfd2->stream.fdtype = FDTYPE_DOUBLE;
|
||||
xfd2->stream.dtype = XIODATA_2PIPE;
|
||||
}
|
||||
break;
|
||||
|
||||
#if HAVE_DEV_PTMX || HAVE_DEV_PTC
|
||||
case 2: /* pty (master, slave) */
|
||||
{
|
||||
int useptmx;
|
||||
char ptyname[MAXPTYNAMELEN];
|
||||
int ptyfd = -1, ttyfd;
|
||||
|
||||
va_start(ap, how);
|
||||
useptmx = va_arg(ap, int);
|
||||
va_end(ap);
|
||||
|
||||
if (useptmx) {
|
||||
if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) {
|
||||
Warn1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620): %s",
|
||||
strerror(errno));
|
||||
/*!*/
|
||||
} else {
|
||||
;/*0 Info1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620) -> %d", ptyfd);*/
|
||||
}
|
||||
if (ptyfd >= 0) {
|
||||
char *tn = NULL;
|
||||
|
||||
/* we used PTMX before forking */
|
||||
/*0 extern char *ptsname(int);*/
|
||||
/* we used PTMX before forking */
|
||||
/*0 extern char *ptsname(int);*/
|
||||
#if HAVE_GRANTPT /* AIX, not Linux */
|
||||
if (Grantpt(ptyfd)/*!*/ < 0) {
|
||||
Warn2("grantpt(%d): %s", ptyfd, strerror(errno));
|
||||
}
|
||||
if (Grantpt(ptyfd)/*!*/ < 0) {
|
||||
Warn2("grantpt(%d): %s", ptyfd, strerror(errno));
|
||||
}
|
||||
#endif /* HAVE_GRANTPT */
|
||||
#if HAVE_UNLOCKPT
|
||||
if (Unlockpt(ptyfd)/*!*/ < 0) {
|
||||
Warn2("unlockpt(%d): %s", ptyfd, strerror(errno));
|
||||
}
|
||||
if (Unlockpt(ptyfd)/*!*/ < 0) {
|
||||
Warn2("unlockpt(%d): %s", ptyfd, strerror(errno));
|
||||
}
|
||||
#endif /* HAVE_UNLOCKPT */
|
||||
#if HAVE_PTSNAME /* AIX, not Linux */
|
||||
if ((tn = Ptsname(ptyfd)) == NULL) {
|
||||
Warn2("ptsname(%d): %s", ptyfd, strerror(errno));
|
||||
} else {
|
||||
Notice1("PTY is %s", tn);
|
||||
}
|
||||
if ((tn = Ptsname(ptyfd)) == NULL) {
|
||||
Warn2("ptsname(%d): %s", ptyfd, strerror(errno));
|
||||
} else {
|
||||
Notice1("PTY is %s", tn);
|
||||
}
|
||||
#endif /* HAVE_PTSNAME */
|
||||
#if 0
|
||||
if (tn == NULL) {
|
||||
/*! ttyname_r() */
|
||||
if ((tn = Ttyname(ptyfd)) == NULL) {
|
||||
Warn2("ttyname(%d): %s", ptyfd, strerror(errno));
|
||||
}
|
||||
}
|
||||
strncpy(ptyname, tn, MAXPTYNAMELEN);
|
||||
if (tn == NULL) {
|
||||
/*! ttyname_r() */
|
||||
if ((tn = Ttyname(ptyfd)) == NULL) {
|
||||
Warn2("ttyname(%d): %s", ptyfd, strerror(errno));
|
||||
}
|
||||
}
|
||||
strncpy(ptyname, tn, MAXPTYNAMELEN);
|
||||
#endif
|
||||
if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) {
|
||||
Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno));
|
||||
} else {
|
||||
/*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/
|
||||
}
|
||||
if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) {
|
||||
Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno));
|
||||
} else {
|
||||
/*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/
|
||||
}
|
||||
|
||||
#ifdef I_PUSH
|
||||
/* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */
|
||||
/* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */
|
||||
/* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
|
||||
/* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
|
||||
if (Ioctl(ttyfd, I_FIND, "ldterm") == 0) {
|
||||
Ioctl(ttyfd, I_PUSH, "ptem"); /* 0 */
|
||||
Ioctl(ttyfd, I_PUSH, "ldterm"); /* 0 */
|
||||
Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */
|
||||
}
|
||||
/* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */
|
||||
/* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */
|
||||
/* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
|
||||
/* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
|
||||
if (Ioctl(ttyfd, I_FIND, "ldterm") == 0) {
|
||||
Ioctl(ttyfd, I_PUSH, "ptem"); /* 0 */
|
||||
Ioctl(ttyfd, I_PUSH, "ldterm"); /* 0 */
|
||||
Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if HAVE_OPENPTY
|
||||
if (ptyfd < 0) {
|
||||
int result;
|
||||
if ((result = Openpty(&ptyfd, &ttyfd, ptyname, NULL, NULL)) < 0) {
|
||||
Error4("openpty(%p, %p, %p, NULL, NULL): %s",
|
||||
&ptyfd, &ttyfd, ptyname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
Notice1("PTY is %s", ptyname);
|
||||
}
|
||||
#endif /* HAVE_OPENPTY */
|
||||
assert(xfd1->stream.fdtype == FDTYPE_SINGLE);
|
||||
xfd1->stream.fd1 = ttyfd;
|
||||
assert(xfd2->stream.fdtype == FDTYPE_SINGLE);
|
||||
xfd2->stream.fd1 = ptyfd;
|
||||
}
|
||||
break;
|
||||
#endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */
|
||||
}
|
||||
#if HAVE_OPENPTY
|
||||
if (ptyfd < 0) {
|
||||
int result;
|
||||
if ((result = Openpty(&ptyfd, &ttyfd, ptyname, NULL, NULL)) < 0) {
|
||||
Error4("openpty(%p, %p, %p, NULL, NULL): %s",
|
||||
&ptyfd, &ttyfd, ptyname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
Notice1("PTY is %s", ptyname);
|
||||
}
|
||||
#endif /* HAVE_OPENPTY */
|
||||
|
||||
default:
|
||||
Error1("undefined socketpair mechanism %d", how);
|
||||
xiofreefd(xfd1); xiofreefd(xfd2);
|
||||
return -1;
|
||||
if (Tcgetattr(ttyfd, &termarg) < 0) {
|
||||
Error3("tcgetattr(%d, %p): %s",
|
||||
ttyfd, &termarg, strerror(errno));
|
||||
}
|
||||
#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;
|
||||
*xfd2p = xfd2;
|
||||
*ttyfdp = ttyfd;
|
||||
*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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user