From 515c305a7fa83c1348c6058d8fdadae4f7609f75 Mon Sep 17 00:00:00 2001
From: Gerhard Rieger Socat version 2 can concatenate multiple modules and transfer data between
+ them bidirectionally.
+ 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.
+ 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.
+ 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 inter addresses
+ can be concatenated to an address chain; however, an endpoint
+ address that just provides file descriptors must be the last component
+ of an address chain.
+ The socat invocation takes two address chains, opens them, and transfers
+ data between them.
+ 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.
+ The (bidirectional) inter addresses that are available with a socat
+ implementation can be listed with the following command:
+ A full socat 2.0.0-b3 program provides the following inter addresses:
+ Inter addresses have two interfaces. In most cases one of
+ these can be seen as a data interface, where arbitrary data
+ traffic may occur, and the other as protocol interface where the
+ transferred data has to follow some rules like socks and HTTP protocol, or
+ valid encryption.
+ Bidirectional inter addresses are usually implemented such that their data
+ interface is on the "left" side, and the protocol interface on the "right"
+ side.
+ 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 reverse direction by preceding their keyword with
+ ˆ.
+ 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:
+ 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.
+ Like in socat version 1, it is possible to specify unidirectional transfers
+ with version 2. Use socat options -u or
+ -U.
+ Unidirectional transfer must be supported by the involved inter addresses;
+ e.g., SSL requires a bidirectional channel for negotiation of encryption
+ parameters etc.
+ It is possible to mix uni- and bidirectional transfers within one address
+ chain: Think of a simple file transfer over SSL.
+ The socat help function can tell us which address types support which kinds
+ of transfer: gives the following output:
+Socat address chains
+
+
+Introduction
+Example 1: OpenSSL via HTTP proxy
+
+
+socat - "OPENSSL,verify=0 | PROXY:secure.domain.com:443 | TCP:proxy.domain.com:8080"
+
+
+Address chain basics
+
+
+
+
+
+
+
+name description
+NOP transfers data unmodified
+OPENSSL-CLIENT performs OpenSSL client negotiation, then
+ encrypts/decrypts data
+OPENSSL-SERVER performs OpenSSL server negotiation, then
+ encrypts/decrypts data
+PROXY performs proxy CONNECT client negotiation, then
+ transfers data unmodified
+SOCKS4 performs socks 4 client negotiation, then
+ transfers data unmodified
+SOCKS4A performs socks 4a client negotiation, then
+ transfers data unmodified
+SOCKS5 performs socks 5 TCP client negotiation, then
+ transfers data unmodified
+TEST appends > to forward, and < to reversely
+ transferred blocks
+EXEC invokes a program
+ (see socat-exec.html), then transfers data unmodified
+
+SYSTEM invokes the shell (see socat-exec.html), then transfers data unmodified Reverse address use
+
+Example 2:
+
+Unidirectional data transfer
+
+ openssl-server rwb b groups=CHILD,RETRY,OPENSSL
+ openssl-server:<port> rwb groups=FD,SOCKET,LISTEN,CHILD,RETRY,RANGE,IP4,IP6,TCP,OPENSSL
+
The rwb b 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. +
+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. +
+ + +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. +
+Note: in version 1, the dual specification was like + righttoleft!!lefttoright. In version 2, it is: + lefttoright%righttoleft. This is the only major incompatibility + between versions 1 and 2. +
+With the few already available inter address types, this feature has no + practical use except with exec and system type + addresses. However, the general function shall be described using the + hypothetical inter address types gzip and gunzip. +
+Let us design these inter address types: gzip 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. + +
+gunzip reads gzip compressed data on its left side and writes the + raw uncompressed data on its right side. +
+socat can combine these to provide a bidirectional compress/decompress
+ function:
+gzip%gunzip
+
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. +
+When the reverse functionality is desired this arrangement does the job:
+gunzip%gzip
+
socat provides the fork address option for uses like network + servers where multiple clients can connect and are handled in parallel in + different socat sub processes. +
+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. +
+ + + +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. +
+Think of several socat1 like processes somehow combined - with an abstract + operator || : +
+ + socat - openssl || socat - proxy:secure.domain.com || socat - tcp:proxy.domain.com:8080 + +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. +
+Here is the socat version 2 command line of example 1:
+socat - "OPENSSL,verify=0 | PROXY:secure.domain.com:443 | TCP:proxy.domain.com:8080"
+
A schematic representation of how this is realized in socat:
+STDIO - engine[thread 0] - OPENSSL - socket pair - (FD) - engine[thread 1]
+- PROXY - socket pair - (FD) - engine[thread 2] - TCP
+
where FD means a trivial address similar to the FD (file descriptor) address + type. +
+For debugging address chains it proved useful to write down two lines and to note the actual file descriptor numbers:
+STDIO ^ OPENSSL | ^ PROXY | ^ TCP + 0,1 ^ 6 | 7 ^ 4 | 5 ^ 3+
The symbol ˆ means a socat transfer engine. +
+ +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: +
+Example 2 command line:
+socat TCP-LISTEN:443,reuseaddr,fork "^OPENSSL-SERVER,cert=server.pem |
+ TCP:somehost:80"
+
Schematic representation:
+TCP-LISTEN - engine[thread 0] - (FD) - socket pair - OPENSSL-SERVER -
+ engine[thread 1] - TCP
+
Debug schema:
+
+ TCP-L ^ | SSL-SERV ^ TCP + 3 ^ 5 | 6 ^ 4+ + + +
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. +
+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 socat-exec.html). +
+The factors to consider for these file dscriptors are: +
+This table lists the available communication types and their + properties:
+comm.type | half close with close() | allows shutdown | avoids buffering | TCP/IPv4 |
---|---|---|---|---|
socketpairs | OK | OK | no | no |
socketpair | no | OK | no | no |
pipes | OK | no | no | no |
ptys | OK | no | yes | no |
tcp | no | yes | no | yes |
The default is socketpairs. +
+The overall communication type can be chosen using the -c 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) +
+ +Copyright: Gerhard Rieger 2009From its very beginning socat provided the EXEC and SYSTEM + 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. +
+ +Currently socat provides three contexts (interfaces) for program or script + execution: +
Note: The endpoint and the unidirectional inter address + 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. +
+ +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): +
+"SOCKS:... | OPENSSL-CLIENT | TCP:..."
If you have a program that implements a new encryption protocol the chain + could be changed to: +
+"SOCKS:... | EXEC:myencrypt.sh | TCP:..."
The complete example:
+socat - "SOCKS:www.domain.com:80 | EXEC:myencrypt.sh | TCP:encrypt.secure.org:444"
The myencrypt.sh 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. +
+The myencrypt.sh script might log to syslog, its own log + file, or to stderr - this is independend of socat. It might have almost + arbitrary side effects. +
+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). +
+The socat source distribution contains two example scripts that focus on + partial aspects: +
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. +
+socat - "exec1:gzip % exec1:gunzip | tcp:remotehost:port"
+
The % character creates a dual communication context where different + inter addresses are used for left-to-right and right-to-left transer (see + socat-addresschain.html#dual. socat + generates stdin/stdout file descriptors for both programs independently. +
+ +
+Copyright: Gerhard Rieger 2009
+License: GNU Free Documentation License (FDL)
+
socat -u TCP4-LISTEN:3334,reuseaddr,fork \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 ',':
diff --git a/sycls.c b/sycls.c
index 14766f3..6827e03 100644
--- a/sycls.c
+++ b/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;
diff --git a/test.sh b/test.sh
index d3d46c3..4e11aa0 100755
--- a/test.sh
+++ b/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
diff --git a/xio-creat.c b/xio-creat.c
index a5eafc0..2faf9f0 100644
--- a/xio-creat.c
+++ b/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;
diff --git a/xio-exec.c b/xio-exec.c
index 03f7abe..7f6364f 100644
--- a/xio-exec.c
+++ b/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(":") };
+/* 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(":") };
+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(":") };
+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(":") };
+/* 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(":") };
-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(":") };
-
+/* 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 };
diff --git a/xio-exec.h b/xio-exec.h
index d70a140..5ebec47 100644
--- a/xio-exec.h
+++ b/xio-exec.h
@@ -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;
diff --git a/xio-fd.c b/xio-fd.c
index 2fa96cb..7006d11 100644
--- a/xio-fd.c
+++ b/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 };
diff --git a/xio-fd.h b/xio-fd.h
index 7d06ac7..f1460bd 100644
--- a/xio-fd.h
+++ b/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) */
diff --git a/xio-fdnum.c b/xio-fdnum.c
index 1b8143e..1b73892 100644
--- a/xio-fdnum.c
+++ b/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(":") };
-const struct xioaddr_endpoint_desc xioaddr_fdnum2 = { XIOADDR_ENDPOINT, "fd", 2, XIOBIT_RDWR, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_fdnum, 0, 0, 0 HELP("::") };
+const 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(":") };
+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("::") };
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);
}
diff --git a/xio-file.c b/xio-file.c
index 626b856..b2ac5e3 100644
--- a/xio-file.c
+++ b/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;
diff --git a/xio-gopen.c b/xio-gopen.c
index 65bd75a..62f049b 100644
--- a/xio-gopen.c
+++ b/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(":") };
@@ -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;
}
diff --git a/xio-interface.c b/xio-interface.c
index 587ea5d..9f3b169 100644
--- a/xio-interface.c
+++ b/xio-interface.c
@@ -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
diff --git a/xio-ipapp.c b/xio-ipapp.c
index 6848680..1136f75 100644
--- a/xio-ipapp.c
+++ b/xio-ipapp.c
@@ -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);
diff --git a/xio-listen.c b/xio-listen.c
index f64a565..12dfd57 100644
--- a/xio-listen.c
+++ b/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)
diff --git a/xio-nop.c b/xio-nop.c
index bc65993..dc6d9c6 100644
--- a/xio-nop.c
+++ b/xio-nop.c
@@ -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;
diff --git a/xio-openssl.c b/xio-openssl.c
index 224b797..52de1ef 100644
--- a/xio-openssl.c
+++ b/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,33 +1089,37 @@ 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;
}
diff --git a/xio-pipe.c b/xio-pipe.c
index 50c4fb6..6b1e439 100644
--- a/xio-pipe.c
+++ b/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);
}
diff --git a/xio-progcall.c b/xio-progcall.c
index 9342cf5..09e613b 100644
--- a/xio-progcall.c
+++ b/xio-progcall.c
@@ -1,5 +1,5 @@
/* source: xio-progcall.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 code dealing with program calls (exec, system) */
@@ -14,6 +14,9 @@
#include "xio-socket.h"
+static int reassignfds(int oldfd1, int oldfd2, int newfd1, int newfd2);
+
+
/* these options are used by address pty too */
#if HAVE_OPENPTY
const struct optdesc opt_openpty = { "openpty", NULL, OPT_OPENPTY, GROUP_PTY, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
@@ -26,677 +29,68 @@ const struct optdesc opt_ptmx = { "ptmx", NULL, OPT_PTMX, GROUP_P
#define MAXPTYNAMELEN 64
-const struct optdesc opt_fdin = { "fdin", NULL, OPT_FDIN, GROUP_FORK, PH_PASTBIGEN, TYPE_USHORT, OFUNC_SPEC };
-const struct optdesc opt_fdout = { "fdout", NULL, OPT_FDOUT, GROUP_FORK, PH_PASTBIGEN, TYPE_USHORT, OFUNC_SPEC };
+const struct optdesc opt_leftfd = { "leftfd", "left", OPT_LEFTFD, GROUP_FORK, PH_PASTBIGEN, TYPE_INT, OFUNC_SPEC };
+const struct optdesc opt_leftinfd = { "leftin", "fdin", OPT_LEFTINFD, GROUP_FORK, PH_PASTBIGEN, TYPE_INT, OFUNC_SPEC };
+const struct optdesc opt_leftoutfd = { "leftout", "fdout", OPT_LEFTOUTFD, GROUP_FORK, PH_PASTBIGEN, TYPE_INT, OFUNC_SPEC };
+const struct optdesc opt_rightfd = { "rightfd", "right", OPT_RIGHTFD, GROUP_FORK, PH_PASTBIGEN, TYPE_INT, OFUNC_SPEC };
+const struct optdesc opt_rightinfd = { "rightinfd", "rightin", OPT_RIGHTINFD, GROUP_FORK, PH_PASTBIGEN, TYPE_INT, OFUNC_SPEC };
+const struct optdesc opt_rightoutfd = { "rightoutfd", "rightout", OPT_RIGHTOUTFD, GROUP_FORK, PH_PASTBIGEN, TYPE_INT, OFUNC_SPEC };
const struct optdesc opt_path = { "path", NULL, OPT_PATH, GROUP_EXEC, PH_PREEXEC, TYPE_STRING, OFUNC_SPEC };
const struct optdesc opt_pipes = { "pipes", NULL, OPT_PIPES, GROUP_FORK, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
#if HAVE_PTY
const struct optdesc opt_pty = { "pty", NULL, OPT_PTY, GROUP_FORK, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
#endif
+const struct optdesc opt_commtype= { "commtype", "c", OPT_COMMTYPE, GROUP_FORK, PH_BIGEN, TYPE_STRING, OFUNC_SPEC };
const struct optdesc opt_stderr = { "stderr", NULL, OPT_STDERR, GROUP_FORK, PH_PASTFORK, TYPE_BOOL, OFUNC_SPEC };
const struct optdesc opt_nofork = { "nofork", NULL, OPT_NOFORK, GROUP_FORK, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
const struct optdesc opt_sighup = { "sighup", NULL, OPT_SIGHUP, GROUP_PARENT, PH_LATE, TYPE_CONST, OFUNC_SIGNAL, SIGHUP };
const struct optdesc opt_sigint = { "sigint", NULL, OPT_SIGINT, GROUP_PARENT, PH_LATE, TYPE_CONST, OFUNC_SIGNAL, SIGINT };
const struct optdesc opt_sigquit = { "sigquit", NULL, OPT_SIGQUIT, GROUP_PARENT, PH_LATE, TYPE_CONST, OFUNC_SIGNAL, SIGQUIT };
-
-#if 0
-
-/* fork for exec/system, but return before exec'ing.
- return=0: is child process
- return>0: is parent process
- return<0: error occurred, assume parent process and no child exists !!!
- */
-int _xioopen_foxec_int(int xioflags, /* XIO_RDONLY etc. */
- struct single *fd,
- unsigned groups,
- struct opt **copts, /* in: opts; out: opts for child */
- int *duptostderr /* out: redirect stderr to output fd */
- ) {
- struct opt *popts; /* parent process options */
- int numleft;
- int d, sv[2], rdpip[2], wrpip[2];
- int rw = (xioflags & XIO_ACCMODE);
- bool usepipes = false;
-#if HAVE_PTY
- int ptyfd = -1, ttyfd = -1;
- bool usebestpty = false; /* use the best available way to open pty */
-#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
- bool useptmx = false; /* use /dev/ptmx or equivalent */
-#endif
-#if HAVE_OPENPTY
- bool useopenpty = false; /* try only openpty */
-#endif /* HAVE_OPENPTY */
- bool usepty = false; /* any of the pty options is selected */
- char ptyname[MAXPTYNAMELEN];
-#endif /* HAVE_PTY */
- pid_t pid = 0; /* mostly int */
- short fdi = 0, fdo = 1;
- short result;
- bool withstderr = false;
- bool nofork = false;
- bool withfork;
-
- popts = moveopts(*copts, GROUP_ALL);
- if (applyopts_single(fd, popts, PH_INIT) < 0) return -1;
- applyopts2(-1, popts, PH_INIT, PH_EARLY);
-
- retropt_bool(popts, OPT_NOFORK, &nofork);
- withfork = !nofork;
-
- retropt_bool(popts, OPT_PIPES, &usepipes);
-#if HAVE_PTY
- retropt_bool(popts, OPT_PTY, &usebestpty);
-#if HAVE_OPENPTY
- retropt_bool(popts, OPT_OPENPTY, &useopenpty);
-#endif
-#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
- retropt_bool(popts, OPT_PTMX, &useptmx);
-#endif
- usepty = (usebestpty
-#if HAVE_OPENPTY
- || useopenpty
-#endif
-#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
- || useptmx
-#endif
- );
- if (usepipes && usepty) {
- Warn("_xioopen_foxec(): options \"pipes\" and \"pty\" must not be specified together; ignoring \"pipes\"");
- usepipes = false;
+int getcommtype(const char *commname) {
+ struct wordent commnames[] = {
+ { "pipes", (void *)XIOCOMM_PIPES },
+ { "pty", (void *)XIOCOMM_PTY },
+ { "ptys", (void *)XIOCOMM_PTYS },
+ { "socketpair", (void *)XIOCOMM_SOCKETPAIR },
+ { "socketpairs", (void *)XIOCOMM_SOCKETPAIRS },
+ { "tcp", (void *)XIOCOMM_TCP },
+ { "tcp4", (void *)XIOCOMM_TCP4 },
+ { "tcp4listen", (void *)XIOCOMM_TCP4_LISTEN },
+ { NULL }
+ } ;
+ const struct wordent *comm_ent;
+ comm_ent = keyw((struct wordent *)commnames, commname,
+ sizeof(commnames)/sizeof(struct wordent));
+ if (!comm_ent) {
+ return -1;
}
-#endif /* HAVE_PTY */
- retropt_ushort(popts, OPT_FDIN, (unsigned short *)&fdi);
- retropt_ushort(popts, OPT_FDOUT, (unsigned short *)&fdo);
-
- if (rw == XIO_WRONLY) {
- if (fd->howtoclose == XIOCLOSE_UNSPEC) {
- fd->howtoclose = XIOCLOSE_SLEEP_SIGTERM;
- }
- }
- if (withfork) {
- if (!(xioflags&XIO_MAYCHILD)) {
- Error("cannot fork off child process here");
- /*!! free something */
- return -1;
- }
- fd->flags |= XIO_DOESCHILD;
-
-#if HAVE_PTY
- Notice2("forking off child, using %s for %s",
- &("socket\0\0pipes\0\0\0pty\0\0\0\0\0"[(usepipes<<3)|(usepty<<4)]),
- ddirection[rw]);
-#else
- Notice2("forking off child, using %s for %s",
- &("socket\0\0pipes\0\0\0"[(usepipes<<3)]),
- ddirection[rw]);
-#endif /* HAVE_PTY */
- }
- applyopts(-1, popts, PH_PREBIGEN);
-
- if (!withfork) {
- /*0 struct single *stream1, *stream2;*/
-
- free(*copts);
- *copts = moveopts(popts, GROUP_ALL);
- /* what if WE are sock1 ? */
-#if 1
- if (!(xioflags & XIO_MAYEXEC /* means exec+nofork */)) {
- Error("nofork option is not allowed here");
- /*!! free something */
- return -1;
- }
- fd->flags |= XIO_DOESEXEC;
-#else /*!! */
- if (sock1 == NULL) {
- Fatal("nofork option must no be applied to first socat address");
- }
-#endif
- if (fd->howtoclose == XIOCLOSE_UNSPEC) {
- fd->howtoclose = XIOCLOSE_CLOSE;
- }
-
-#if 0 /*!! */
- if (sock1->tag == XIO_TAG_DUAL) {
- stream1 = &sock1->dual.stream[0]->stream;
- stream2 = &sock1->dual.stream[1]->stream;
- } else {
- stream1 = &sock1->stream;
- stream2 = &sock1->stream;
- }
- if (stream1->dtype == DATA_READLINE || stream2->dtype == DATA_READLINE ||
- stream1->dtype == DATA_OPENSSL || stream2->dtype == DATA_OPENSSL
- ) {
- Error("with option nofork, openssl and readline in address1 do not work");
- }
- if (stream1->lineterm != LINETERM_RAW ||
- stream2->lineterm != LINETERM_RAW ||
- stream1->ignoreeof || stream2->ignoreeof) {
- Warn("due to option nofork, address1 options for lineterm and igoreeof do not apply");
- }
-#endif
-
- /*! problem: when fdi==WRFD(sock[0]) or fdo==RDFD(sock[0]) */
- if (rw != XIO_WRONLY) {
- if (XIO_GETRDFD(sock[0]/*!!*/) == fdi) {
- if (Fcntl_l(fdi, F_SETFD, 0) < 0) {
- Warn2("fcntl(%d, F_SETFD, 0): %s", fdi, strerror(errno));
- }
- if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) {
- Error3("dup2(%d, %d): %s",
- XIO_GETRDFD(sock[0]), fdi, strerror(errno));
- }
- /*0 Info2("dup2(%d, %d)", XIO_GETRDFD(sock[0]), fdi);*/
- } else {
- if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) {
- Error3("dup2(%d, %d): %s",
- XIO_GETRDFD(sock[0]), fdi, strerror(errno));
- }
- /*0 Info2("dup2(%d, %d)", XIO_GETRDFD(sock[0]), fdi);*/
- }
- }
- if (rw != XIO_RDONLY) {
- if (XIO_GETWRFD(sock[0]) == fdo) {
- if (Fcntl_l(fdo, F_SETFD, 0) < 0) {
- Warn2("fcntl(%d, F_SETFD, 0): %s", fdo, strerror(errno));
- }
- if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) {
- Error3("dup2(%d, %d): %s)",
- XIO_GETWRFD(sock[0]), fdo, strerror(errno));
- }
- /*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/
- } else {
- if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) {
- Error3("dup2(%d, %d): %s)",
- XIO_GETWRFD(sock[0]), fdo, strerror(errno));
- }
- /*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/
- }
- }
- } else
-#if HAVE_PTY
- if (usepty) {
-
-#if defined(HAVE_DEV_PTMX)
-# define PTMX "/dev/ptmx" /* Linux */
-#elif HAVE_DEV_PTC
-# define PTMX "/dev/ptc" /* AIX 4.3.3 */
-#endif
- fd->dtype = XIODATA_PTY;
- if (fd->howtoshut == XIOSHUT_UNSPEC) {
- fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP;
- }
- if (fd->howtoclose == XIOCLOSE_UNSPEC) {
- fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM;
- }
-
-#if HAVE_DEV_PTMX || HAVE_DEV_PTC
- if (usebestpty || useptmx) {
- if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) {
- Warn1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620): %s",
- strerror(errno));
- /*!*/
- } else {
- /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", PTMX, ptyfd);*/
- }
- if (ptyfd >= 0 && ttyfd < 0) {
- char *tn = NULL;
- /* we used PTMX before forking */
- extern char *ptsname(int);
-#if HAVE_GRANTPT /* AIX, not Linux */
- if (Grantpt(ptyfd)/*!*/ < 0) {
- Warn2("grantpt(%d): %s", ptyfd, strerror(errno));
- }
-#endif /* HAVE_GRANTPT */
-#if HAVE_UNLOCKPT
- if (Unlockpt(ptyfd)/*!*/ < 0) {
- Warn2("unlockpt(%d): %s", ptyfd, strerror(errno));
- }
-#endif /* HAVE_UNLOCKPT */
-#if HAVE_PTSNAME /* AIX, not Linux */
- if ((tn = Ptsname(ptyfd)) == NULL) {
- Warn2("ptsname(%d): %s", ptyfd, strerror(errno));
- }
-#endif /* HAVE_PTSNAME */
- if (tn == NULL) {
- if ((tn = Ttyname(ptyfd)) == NULL) {
- Warn2("ttyname(%d): %s", ptyfd, strerror(errno));
- }
- }
- strncpy(ptyname, tn, MAXPTYNAMELEN); /*! ttyname_r() */
- if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) {
- Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno));
- } else {
- /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/
- }
-
-#ifdef I_PUSH
- /* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */
- /* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */
- /* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
- /* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
- if (Ioctl(ttyfd, I_FIND, "ldterm") == 0) {
- Ioctl(ttyfd, I_PUSH, "ptem"); /* 0 */
- Ioctl(ttyfd, I_PUSH, "ldterm"); /* 0 */
- Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */
- }
-#endif
-
-#if 0 /* the following block need not work */
-
- if (ttyfd >= 0 && ((tn = Ttyname(ttyfd)) == NULL)) {
- Warn2("ttyname(%d): %s", ttyfd, strerror(errno));
- }
- if (tn == NULL) {
- Error("could not open pty");
- return STAT_NORETRY;
- }
-#endif
- Info1("opened pseudo terminal %s", tn);
- }
- }
-#endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */
-#if HAVE_OPENPTY
- if (ptyfd < 0) {
- int result;
- if ((result = Openpty(&ptyfd, &ttyfd, ptyname, NULL, NULL)) < 0) {
- Error4("openpty(%p, %p, %p, NULL, NULL): %s",
- &ptyfd, &ttyfd, ptyname, strerror(errno));
- return -1;
- }
- }
-#endif /* HAVE_OPENPTY */
- free(*copts);
- if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
- return STAT_RETRYLATER;
- }
- applyopts_cloexec(ptyfd, popts);/*!*/
- if (fd->howtoshut == XIOSHUT_UNSPEC) {
- fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP;
- }
- if (fd->howtoclose == XIOCLOSE_UNSPEC) {
- fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM;
- }
-
- /* this for parent, was after fork */
- applyopts(ptyfd, popts, PH_FD);
- applyopts(ptyfd, popts, PH_LATE);
- if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
-
- fd->fd1 = ptyfd;
- fd->fdtype = FDTYPE_SINGLE;
-
- /* this for child, was after fork */
- applyopts(ttyfd, *copts, PH_FD);
- } else
-#endif /* HAVE_PTY */
- if (usepipes) {
- struct opt *popts2, *copts2;
-
- if (rw == XIO_RDWR) {
- fd->dtype = XIODATA_2PIPE;
- }
- if (fd->howtoshut == XIOSHUT_UNSPEC) {
- fd->howtoshut = XIOSHUT_CLOSE;
- }
- if (fd->howtoclose == XIOCLOSE_UNSPEC) {
- fd->howtoclose = XIOCLOSE_CLOSE;
- }
-
- if (rw != XIO_WRONLY) {
- if (Pipe(rdpip) < 0) {
- Error2("pipe(%p): %s", rdpip, strerror(errno));
- return STAT_RETRYLATER;
- }
- } else {
- rdpip[0] = rdpip[1] = -1;
- }
- /*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/
- /* rdpip[0]: read by socat; rdpip[1]: write by child */
- free(*copts);
- if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS))
- == NULL) {
- return STAT_RETRYLATER;
- }
-
- popts2 = copyopts(popts, GROUP_ALL);
- copts2 = copyopts(*copts, GROUP_ALL);
-
- if (rw != XIO_WRONLY) {
- applyopts_cloexec(rdpip[0], popts);
- applyopts(rdpip[0], popts, PH_FD);
- applyopts(rdpip[1], *copts, PH_FD);
- }
-
- if (rw != XIO_RDONLY) {
- if (Pipe(wrpip) < 0) {
- Error2("pipe(%p): %s", wrpip, strerror(errno));
- return STAT_RETRYLATER;
- }
- } else {
- wrpip[0] = wrpip[1] = -1;
- }
- /*0 Info2("pipe({%d,%d})", wrpip[0], wrpip[1]);*/
-
- /* wrpip[1]: write by socat; wrpip[0]: read by child */
- if (rw != XIO_RDONLY) {
- applyopts_cloexec(wrpip[1], popts2);
- applyopts(wrpip[1], popts2, PH_FD);
- applyopts(wrpip[0], copts2, PH_FD);
- }
-
- /* this for parent, was after fork */
- switch (rw) {
- case XIO_RDONLY:
- fd->fd1 = rdpip[0];
- fd->fdtype = FDTYPE_SINGLE;
- break;
- case XIO_WRONLY:
- fd->fd1 = wrpip[1];
- fd->fdtype = FDTYPE_SINGLE;
- break;
- case XIO_RDWR:
- fd->fd1 = rdpip[0];
- fd->fd2 = wrpip[1];
- fd->fdtype = FDTYPE_DOUBLE;
- break;
- }
- applyopts(fd->fd1, popts, PH_FD);
- applyopts(fd->fd1, popts, PH_LATE);
- if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
- } else {
- int socktype = SOCK_STREAM;
- int protocol = 0;
- d = AF_UNIX;
- retropt_int(popts, OPT_SO_TYPE, &socktype);
- result = Socketpair(d, socktype, protocol, sv);
- if (result < 0) {
- Error5("socketpair(%d, %d, %d, %p): %s",
- d, socktype, protocol, sv, strerror(errno));
- return STAT_RETRYLATER;
- }
- /*0 Info5("socketpair(%d, %d, %d, {%d,%d})",
- d, type, protocol, sv[0], sv[1]);*/
- free(*copts);
- if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
- return STAT_RETRYLATER;
- }
- applyopts(sv[0], *copts, PH_PASTSOCKET);
- applyopts(sv[1], popts, PH_PASTSOCKET);
-
- applyopts_cloexec(sv[0], *copts);
- applyopts(sv[0], *copts, PH_FD);
- applyopts(sv[1], popts, PH_FD);
-
- applyopts(sv[0], *copts, PH_PREBIND);
- applyopts(sv[0], *copts, PH_BIND);
- applyopts(sv[0], *copts, PH_PASTBIND);
- applyopts(sv[1], popts, PH_PREBIND);
- applyopts(sv[1], popts, PH_BIND);
- applyopts(sv[1], popts, PH_PASTBIND);
-
- if (fd->howtoshut == XIOSHUT_UNSPEC) {
- fd->howtoshut = XIOSHUT_DOWN;
- }
- if (fd->howtoclose == XIOCLOSE_UNSPEC) {
- fd->howtoclose = XIOCLOSE_SIGTERM;
- }
-
- /* this for parent, was after fork */
- fd->fd1 = sv[0];
- fd->fdtype = FDTYPE_SINGLE;
- applyopts(fd->fd1, popts, PH_FD);
- applyopts(fd->fd1, popts, PH_LATE);
- if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
- }
- /*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL)
- return STAT_RETRYLATER;*/
- retropt_bool(*copts, OPT_STDERR, &withstderr);
-#if 0
- if (Signal(SIGCHLD, childdied) == SIG_ERR) {
- Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
- }
-#endif
-
- if (withfork) {
- const char *forkwaitstring;
- int forkwaitsecs = 0;
- sigset_t set, oldset;
-
- sigemptyset(&set);
- sigaddset(&set, SIGCHLD);
-
- Sigprocmask(SIG_BLOCK, &set, &oldset); /* disable SIGCHLD */
-
- pid = Fork();
- if (pid < 0) {
- Sigprocmask(SIG_SETMASK, &oldset, NULL);
- Error1("fork(): %s", strerror(errno));
- return STAT_RETRYLATER;
- }
- /* gdb recommends to have env controlled sleep after fork */
- if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
- forkwaitsecs = atoi(forkwaitstring);
- Sleep(forkwaitsecs);
- }
-
- if (pid > 0) {
- /* for parent (this is our socat process) */
- xiosigchld_register(pid, xiosigaction_child, fd);
- Sigprocmask(SIG_SETMASK, &oldset, NULL); /* disable SIGCHLD */
- }
-
- if (pid == 0) { /* child */
- /* drop parents locks, reset FIPS... */
- if (xio_forked_inchild() != 0) {
- Exit(1);
- }
- Sigprocmask(SIG_SETMASK, &oldset, NULL); /* disable SIGCHLD */
- }
- }
- if (!withfork || pid == 0) { /* child */
- uid_t user;
- gid_t group;
-
- if (withfork) {
- if (Signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
- Warn1("signal(SIGCHLD, SIG_IGN): %s", strerror(errno));
- }
-
-#if HAVE_PTY
- if (usepty) {
- if (rw != XIO_RDONLY && fdi != ttyfd) {
- if (Dup2(ttyfd, fdi) < 0) {
- Error3("dup2(%d, %d): %s", ttyfd, fdi, strerror(errno));
- return STAT_RETRYLATER; }
- /*0 Info2("dup2(%d, %d)", ttyfd, fdi);*/
- }
- if (rw != XIO_WRONLY && fdo != ttyfd) {
- if (Dup2(ttyfd, fdo) < 0) {
- Error3("dup2(%d, %d): %s", ttyfd, fdo, strerror(errno));
- return STAT_RETRYLATER; }
- /*0 Info2("dup2(%d, %d)", ttyfd, fdo);*/
- }
- if ((rw == XIO_RDONLY || fdi != ttyfd) &&
- (rw == XIO_WRONLY || fdo != ttyfd)) {
- applyopts_cloexec(ttyfd, *copts);
- }
-
- applyopts(ttyfd, *copts, PH_LATE);
-
- applyopts(ttyfd, *copts, PH_LATE2);
- } else
-#endif /* HAVE_PTY */
- if (usepipes) {
- /* we might have a temporary conflict between what FDs are
- currently allocated, and which are to be used. We try to find
- a graceful solution via temporary descriptors */
- int tmpi, tmpo;
-
- if (fdi == rdpip[1]) { /* a conflict here */
- if ((tmpi = Dup(wrpip[0])) < 0) {
- Error2("dup(%d): %s", wrpip[0], strerror(errno));
- return STAT_RETRYLATER;
- }
- /*0 Info2("dup(%d) -> %d", wrpip[0], tmpi);*/
- rdpip[1] = tmpi;
- }
- if (fdo == wrpip[0]) { /* a conflict here */
- if ((tmpo = Dup(rdpip[1])) < 0) {
- Error2("dup(%d): %s", rdpip[1], strerror(errno));
- return STAT_RETRYLATER;
- }
- /*0 Info2("dup(%d) -> %d", rdpip[1], tmpo);*/
- wrpip[0] = tmpo;
- }
-
- if (rw != XIO_WRONLY && rdpip[1] != fdo) {
- if (Dup2(rdpip[1], fdo) < 0) {
- Error3("dup2(%d, %d): %s", rdpip[1], fdo, strerror(errno));
- return STAT_RETRYLATER;
- }
- Close(rdpip[1]);
- /*0 Info2("dup2(%d, %d)", rdpip[1], fdo);*/
- /*0 applyopts_cloexec(fdo, *copts);*/
- }
- if (rw != XIO_RDONLY && wrpip[0] != fdi) {
- if (Dup2(wrpip[0], fdi) < 0) {
- Error3("dup2(%d, %d): %s", wrpip[0], fdi, strerror(errno));
- return STAT_RETRYLATER;
- }
- Close(wrpip[0]);
- /*0 Info2("dup2(%d, %d)", wrpip[0], fdi);*/
- /*0 applyopts_cloexec(wrpip[0], *copts);*/ /* option is already consumed! */
- /* applyopts_cloexec(fdi, *copts);*/ /* option is already consumed! */
- }
-
- applyopts(fdi, *copts, PH_LATE);
- applyopts(fdo, *copts, PH_LATE);
- applyopts(fdi, *copts, PH_LATE2);
- applyopts(fdo, *copts, PH_LATE2);
-
- } else { /* socketpair */
- if (rw != XIO_RDONLY && fdi != sv[1]) {
- if (Dup2(sv[1], fdi) < 0) {
- Error3("dup2(%d, %d): %s", sv[1], fdi, strerror(errno));
- return STAT_RETRYLATER; }
- /*0 Info2("dup2(%d, %d)", sv[1], fdi);*/
- }
- if (rw != XIO_WRONLY && fdo != sv[1]) {
- if (Dup2(sv[1], fdo) < 0) {
- Error3("dup2(%d, %d): %s", sv[1], fdo, strerror(errno));
- return STAT_RETRYLATER; }
- /*0 Info2("dup2(%d, %d)", sv[1], fdo);*/
- }
- if (fdi != sv[1] && fdo != sv[1]) {
- applyopts_cloexec(sv[1], *copts);
- }
-
- applyopts(fdi, *copts, PH_LATE);
- applyopts(fdi, *copts, PH_LATE2);
- }
- } /* withfork */
- else {
- applyopts(-1, *copts, PH_LATE);
- applyopts(-1, *copts, PH_LATE2);
- }
-
- /* what to do with stderr? */
- if (withstderr) {
- /* handle it just like ordinary process output, i.e. copy output fd */
- if (!withfork) {
- if (Dup2(fdo, 2) < 0) {
- Error2("dup2(%d, 2): %s", fdo, strerror(errno));
- }
- /*0 Info1("dup2(%d, 2)", fdo);*/
- } else
-#if HAVE_PTY
- if (usepty) {
- if (Dup2(ttyfd, 2) < 0) {
- Error2("dup2(%d, 2): %s", ttyfd, strerror(errno));
- }
- /*0 Info1("dup2(%d, 2)", ttyfd);*/
- } else
-#endif /* HAVE_PTY */
- if (usepipes) {
- if (Dup2(/*rdpip[1]*/ fdo, 2) < 0) {
- Error2("dup2(%d, 2): %s", /*rdpip[1]*/ fdo, strerror(errno));
- }
- /*0 Info1("dup2(%d, 2)", rdpip[1]);*/
- } else {
- if (Dup2(sv[1], 2) < 0) {
- Error2("dup2(%d, 2): %s", sv[1], strerror(errno));
- }
- /*0 Info1("dup2(%d, 2)", sv[1]);*/
- }
- }
- _xioopen_setdelayeduser();
- /* set group before user - maybe you are not permitted afterwards */
- if (retropt_gidt(*copts, OPT_SETGID, &group) >= 0) {
- Setgid(group);
- }
- if (retropt_uidt(*copts, OPT_SETUID, &user) >= 0) {
- Setuid(user);
- }
- return 0; /* indicate child process */
- }
-
- /* for parent (this is our socat process) */
- Notice1("forked off child process "F_pid, pid);
-
-#if 0
- if ((popts = copyopts(*copts,
- GROUP_FD|GROUP_TERMIOS|GROUP_FORK|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_FIFO)) == NULL)
- return STAT_RETRYLATER;
-#endif
-
- if (0) {
- ; /* for canonical reasons */
-#if HAVE_PTY
- } else if (usepty) {
- if (Close(ttyfd) < 0) {
- Info2("close(%d): %s", ttyfd, strerror(errno));
- }
-#endif /* HAVE_PTY */
-#if 1
- } else if (usepipes) {
- if (wrpip[0] >= 0) Close(wrpip[0]);
- if (rdpip[1] >= 0) Close(rdpip[1]);
- } else { /* socketpair() */
- Close(sv[1]);
- }
-#endif
- fd->child.pid = pid;
-
- if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
- applyopts_signal(fd, popts);
- if ((numleft = leftopts(popts)) > 0) {
- Error1("%d option(s) could not be used", numleft);
- showleft(popts);
- return STAT_NORETRY;
- }
-
- return pid; /* indicate parent (main) process */
+ return (int)comm_ent->desc;
}
-#endif /* 0 */
-
-
/* fork for exec/system, but return before exec'ing.
return=0: is child process
return>0: is parent process
return<0: error occurred, assume parent process and no child exists !!!
+ function formerly known as _xioopen_foxec()
*/
-int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
- struct single *fd,
- unsigned groups,
+int _xioopen_progcall(int xioflags, /* XIO_RDONLY etc. */
+ struct single *xfd,
+ unsigned groups,
struct opt **copts, /* in: opts; out: opts for child */
- int *duptostderr
+ int *duptostderr,
+ bool inter, /* is interaddr, not endpoint */
+ int form /* with interaddr: =2: FDs 1,0--4,3
+ =1: FDs 1--0 */
) {
+ struct single *fd = xfd;
struct opt *popts; /* parent process options */
int numleft;
int sv[2], rdpip[2], wrpip[2];
+ int saverfd, savewfd; /* with inter addr, save assigned right fds */
int rw = (xioflags & XIO_ACCMODE);
+ char *commname;
+ int commtype = XIOCOMM_SOCKETPAIRS;
bool usepipes = false;
#if HAVE_PTY
int ptyfd = -1, ttyfd = -1;
@@ -711,7 +105,12 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
char ptyname[MAXPTYNAMELEN];
#endif /* HAVE_PTY */
pid_t pid = 0; /* mostly int */
- short fdi = 0, fdo = 1;
+ int leftfd[2] = { 0, 1 };
+# define fdi (leftfd[0])
+# define fdo (leftfd[1])
+ int rightfd[2] = { 3, 4 };
+# define rightin (rightfd[0])
+# define rightout (rightfd[1])
short result;
bool withstderr = false;
bool nofork = false;
@@ -724,6 +123,13 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
retropt_bool(popts, OPT_NOFORK, &nofork);
withfork = !nofork;
+ if ((retropt_string(popts, OPT_COMMTYPE, &commname)) >= 0) {
+ if ((commtype = getcommtype(commname)) < 0) {
+ Error1("bad communication type \"%s\"", commname);
+ commtype = XIOCOMM_SOCKETPAIRS;
+ }
+ }
+
retropt_bool(popts, OPT_PIPES, &usepipes);
#if HAVE_PTY
retropt_bool(popts, OPT_PTY, &usebestpty);
@@ -746,34 +152,80 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
usepipes = false;
}
#endif /* HAVE_PTY */
- retropt_ushort(popts, OPT_FDIN, (unsigned short *)&fdi);
- retropt_ushort(popts, OPT_FDOUT, (unsigned short *)&fdo);
+ if (usepty) {
+ commtype = XIOCOMM_PTY;
+ } else if (usepipes) {
+ commtype = XIOCOMM_PIPES;
+ }
+
+ /*------------------------------------------------------------------------*/
+ /* retrieve options regarding file descriptors */
+ if (!retropt_int(popts, OPT_LEFTFD, &fdi)) {
+ fdo = fdi;
+ }
+ retropt_int(popts, OPT_LEFTINFD, &fdi);
+ retropt_int(popts, OPT_LEFTOUTFD, &fdo);
+
+ if (!retropt_int(popts, OPT_RIGHTFD, &rightin)) {
+ rightout = rightin;
+ }
+ retropt_int(popts, OPT_RIGHTINFD, &rightin);
+ retropt_int(popts, OPT_RIGHTOUTFD, &rightout);
+ /* when the superordinate communication type provides two distinct fds we
+ cannot pass just one fd to the program */
+ if (rw == XIO_RDWR && rightin==rightout) {
+ struct stat rstat, wstat;
+ if (Fstat(xfd->rfd, &rstat) < 0)
+ Error2("fstat(%d, ...): %s", xfd->rfd, strerror(errno));
+ if (Fstat(xfd->wfd, &wstat) < 0)
+ Error2("fstat(%d, ...): %s", xfd->wfd, strerror(errno));
+ if (memcmp(&rstat, &wstat, sizeof(rstat))) {
+ Error("exec/system: your rightfd options require the same FD for both directions but the communication environment provides two different FDs");
+ }
+ }
+
+ /*------------------------------------------------------------------------*/
if (rw == XIO_WRONLY) {
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_SLEEP_SIGTERM;
}
}
if (withfork) {
+ const char *typename;
if (!(xioflags&XIO_MAYCHILD)) {
- Error("cannot fork off child process here");
+ Error("fork for exec not allowed in this context");
/*!! free something */
return -1;
}
fd->flags |= XIO_DOESCHILD;
+ switch (commtype) {
+ case XIOCOMM_PIPES: typename = "pipes"; break;
#if HAVE_PTY
- Notice2("forking off child, using %s for %s",
- &("socket\0\0pipes\0\0\0pty\0\0\0\0\0"[(usepipes<<3)|(usepty<<4)]),
- ddirection[rw]);
-#else
- Notice2("forking off child, using %s for %s",
- &("socket\0\0pipes\0\0\0"[(usepipes<<3)]),
- ddirection[rw]);
+ case XIOCOMM_PTY: typename = "pty"; break;
+ case XIOCOMM_PTYS: typename = "two pty's"; break;
#endif /* HAVE_PTY */
+ case XIOCOMM_SOCKETPAIR: typename = "socketpair"; break;
+ case XIOCOMM_SOCKETPAIRS: typename = "two socketpairs"; break;
+#if _WITH_TCP
+ case XIOCOMM_TCP: typename = "TCP socket pair"; break;
+ case XIOCOMM_TCP4: typename = "TCP4 socket pair"; break;
+ case XIOCOMM_TCP4_LISTEN: typename = "TCP4 listen socket pair"; break;
+#endif
+ }
+ Notice2("forking off child, using %s for %s",
+ typename, ddirection[rw]);
}
applyopts(-1, popts, PH_PREBIGEN);
+ if (inter) {
+ saverfd = xfd->rfd;
+ savewfd = xfd->wfd;
+ xfd->howtoshut = XIOSHUT_UNSPEC;
+ xfd->howtoclose = XIOCLOSE_UNSPEC;
+ }
+
if (!withfork) {
/*0 struct single *stream1, *stream2;*/
@@ -818,7 +270,7 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
/*! problem: when fdi==WRFD(sock[0]) or fdo==RDFD(sock[0]) */
if (rw != XIO_WRONLY) {
- if (XIO_GETRDFD(sock[0]/*!!*/) == fdi) {
+ if (XIO_GETRDFD(sock[0]/*!!!*/) == fdi) {
if (Fcntl_l(fdi, F_SETFD, 0) < 0) {
Warn2("fcntl(%d, F_SETFD, 0): %s", fdi, strerror(errno));
}
@@ -853,99 +305,32 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
/*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/
}
}
- } else
-#if HAVE_PTY
- if (usepty) {
+ } else /* withfork */
+ /* create fd pair(s), set related xfd parameters, and apply options */
+ switch (commtype) {
+#if HAVE_PTY
+ case XIOCOMM_PTY:
+ /*!indent*/
#if defined(HAVE_DEV_PTMX)
# define PTMX "/dev/ptmx" /* Linux */
#elif HAVE_DEV_PTC
# define PTMX "/dev/ptc" /* AIX 4.3.3 */
#endif
fd->dtype = XIODATA_PTY;
+#if 0
if (fd->howtoshut == XIOSHUT_UNSPEC) {
fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP;
}
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM;
}
-
-#if HAVE_DEV_PTMX || HAVE_DEV_PTC
- if (usebestpty || useptmx) {
- if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) {
- Warn1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620): %s",
- strerror(errno));
- /*!*/
- } else {
- /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", PTMX, ptyfd);*/
- }
- if (ptyfd >= 0 && ttyfd < 0) {
- char *tn = NULL;
- /* we used PTMX before forking */
- extern char *ptsname(int);
-#if HAVE_GRANTPT /* AIX, not Linux */
- if (Grantpt(ptyfd)/*!*/ < 0) {
- Warn2("grantpt(%d): %s", ptyfd, strerror(errno));
- }
-#endif /* HAVE_GRANTPT */
-#if HAVE_UNLOCKPT
- if (Unlockpt(ptyfd)/*!*/ < 0) {
- Warn2("unlockpt(%d): %s", ptyfd, strerror(errno));
- }
-#endif /* HAVE_UNLOCKPT */
-#if HAVE_PTSNAME /* AIX, not Linux */
- if ((tn = Ptsname(ptyfd)) == NULL) {
- Warn2("ptsname(%d): %s", ptyfd, strerror(errno));
- }
-#endif /* HAVE_PTSNAME */
- if (tn == NULL) {
- if ((tn = Ttyname(ptyfd)) == NULL) {
- Warn2("ttyname(%d): %s", ptyfd, strerror(errno));
- }
- }
- strncpy(ptyname, tn, MAXPTYNAMELEN); /*! ttyname_r() */
- if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) {
- Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno));
- } else {
- /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/
- }
-
-#ifdef I_PUSH
- /* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */
- /* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */
- /* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
- /* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
- if (Ioctl(ttyfd, I_FIND, "ldterm") == 0) {
- Ioctl(ttyfd, I_PUSH, "ptem"); /* 0 */
- Ioctl(ttyfd, I_PUSH, "ldterm"); /* 0 */
- Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */
- }
#endif
-#if 0 /* the following block need not work */
+ if (xiopty(usebestpty||useptmx, &ttyfd, &ptyfd) < 0) {
+ return -1;
+ }
- if (ttyfd >= 0 && ((tn = Ttyname(ttyfd)) == NULL)) {
- Warn2("ttyname(%d): %s", ttyfd, strerror(errno));
- }
- if (tn == NULL) {
- Error("could not open pty");
- return -1;
- }
-#endif
- Info1("opened pseudo terminal %s", tn);
- }
- }
-#endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */
-#if HAVE_OPENPTY
- if (ptyfd < 0) {
- int result;
- if ((result = Openpty(&ptyfd, &ttyfd, ptyname, NULL, NULL)) < 0) {
- Error4("openpty(%p, %p, %p, NULL, NULL): %s",
- &ptyfd, &ttyfd, ptyname, strerror(errno));
- return -1;
- }
- }
-#endif /* HAVE_OPENPTY */
free(*copts);
if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
return -1;
@@ -965,20 +350,23 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
applyopts(ptyfd, popts, PH_LATE);
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
- fd->fd1 = ptyfd;
- fd->fdtype = FDTYPE_SINGLE;
+ if (XIOWITHRD(rw)) fd->rfd = ptyfd;
+ if (XIOWITHWR(rw)) fd->wfd = ptyfd;
/* this for child, was after fork */
applyopts(ttyfd, *copts, PH_FD);
- } else
+
+ break;
#endif /* HAVE_PTY */
- if (usepipes) {
+
+ case XIOCOMM_PIPES: {
+ /*!indent*/
struct opt *popts2, *copts2;
if (rw == XIO_RDWR) {
fd->dtype = XIODATA_2PIPE;
}
- if (fd->howtoshut == XIOSHUT_UNSPEC) {
+ if (fd->howtoshut == XIOSHUT_UNSPEC || fd->howtoshut == XIOSHUT_DOWN) {
fd->howtoshut = XIOSHUT_CLOSE;
}
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
@@ -1024,31 +412,30 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
}
/* this for parent, was after fork */
- switch (rw) {
- case XIO_RDONLY:
- fd->fd1 = rdpip[0];
- fd->fdtype = FDTYPE_SINGLE;
- break;
- case XIO_WRONLY:
- fd->fd1 = wrpip[1];
- fd->fdtype = FDTYPE_SINGLE;
- break;
- case XIO_RDWR:
- fd->fd1 = rdpip[0];
- fd->fd2 = wrpip[1];
- fd->fdtype = FDTYPE_DOUBLE;
- break;
- }
- applyopts(fd->fd1, popts, PH_FD);
- applyopts(fd->fd1, popts, PH_LATE);
+ if (XIOWITHRD(rw)) fd->rfd = rdpip[0];
+ if (XIOWITHWR(rw)) fd->wfd = wrpip[1];
+ applyopts(fd->rfd, popts, PH_FD);
+ applyopts(fd->rfd, popts, PH_LATE);
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
- } else {
+ break;
+ }
+
+ case XIOCOMM_SOCKETPAIR: {
+ /*!indent*/
int pf = AF_UNIX;
retropt_int(popts, OPT_PROTOCOL_FAMILY, &pf);
result = xiosocketpair(popts, pf, SOCK_STREAM, 0, sv);
if (result < 0) {
return -1;
}
+
+ if (xfd->howtoshut == XIOSHUT_UNSPEC) {
+ xfd->howtoshut = XIOSHUT_DOWN;
+ }
+ if (xfd->howtoclose == XIOCLOSE_UNSPEC) {
+ xfd->howtoclose = XIOCLOSE_CLOSE;
+ }
+
/*0 Info5("socketpair(%d, %d, %d, {%d,%d})",
d, type, protocol, sv[0], sv[1]);*/
free(*copts);
@@ -1069,7 +456,8 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
applyopts(sv[1], popts, PH_BIND);
applyopts(sv[1], popts, PH_PASTBIND);
- if (fd->howtoshut == XIOSHUT_UNSPEC) {
+Warn1("xio-progcall.c: fd->howtoshut == %d", fd->howtoshut);
+ if (inter || fd->howtoshut == XIOSHUT_UNSPEC) {
fd->howtoshut = XIOSHUT_DOWN;
}
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
@@ -1077,12 +465,143 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
}
/* this for parent, was after fork */
- fd->fd1 = sv[0];
- fd->fdtype = FDTYPE_SINGLE;
- applyopts(fd->fd1, popts, PH_FD);
- applyopts(fd->fd1, popts, PH_LATE);
+ /*!!!*/ Warn2("2: fd->rfd==%d, fd->wfd==%d", fd->rfd, fd->wfd);
+ if (XIOWITHRD(rw)) fd->rfd = sv[0];
+ if (XIOWITHWR(rw)) fd->wfd = sv[0];
+ /*!!!*/ Warn2("3: fd->rfd==%d, fd->wfd==%d", fd->rfd, fd->wfd);
+ applyopts(fd->rfd, popts, PH_FD);
+ applyopts(fd->rfd, popts, PH_LATE);
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
- }
+ }
+ break;
+
+ case XIOCOMM_TCP:
+ case XIOCOMM_TCP4: {
+ /*!indent*/
+ int pf = AF_INET;
+ xiofd_t socatfd, execfd;
+ retropt_int(popts, OPT_PROTOCOL_FAMILY, &pf);
+ if (xiocommpair(commtype, XIOWITHWR(rw), XIOWITHRD(rw),
+ 0, &socatfd, &execfd) < 0) {
+ return -1;
+ }
+ free(*copts);
+ if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
+ return -1;
+ }
+ sv[0] = socatfd.rfd; /*!!! r/w */
+ sv[1] = execfd.wfd;
+ applyopts(socatfd.rfd, *copts, PH_PASTSOCKET);
+ applyopts(execfd.rfd, popts, PH_PASTSOCKET);
+
+ applyopts_cloexec(sv[0], *copts);
+ applyopts(sv[0], *copts, PH_FD);
+ applyopts(sv[1], popts, PH_FD);
+
+ applyopts(sv[0], *copts, PH_PREBIND);
+ applyopts(sv[0], *copts, PH_BIND);
+ applyopts(sv[0], *copts, PH_PASTBIND);
+ applyopts(sv[1], popts, PH_PREBIND);
+ applyopts(sv[1], popts, PH_BIND);
+ applyopts(sv[1], popts, PH_PASTBIND);
+
+Warn1("xio-progcall.c: fd->howtoshut == %d", fd->howtoshut);
+ if (inter || fd->howtoshut == XIOSHUT_UNSPEC) {
+ fd->howtoshut = XIOSHUT_DOWN;
+ }
+ if (fd->howtoclose == XIOCLOSE_UNSPEC) {
+ fd->howtoclose = XIOCLOSE_SIGTERM;
+ }
+
+ /* this for parent, was after fork */
+ if (XIOWITHRD(rw)) fd->rfd = sv[0];
+ if (XIOWITHWR(rw)) fd->wfd = sv[0];
+ applyopts(fd->rfd, popts, PH_FD);
+ applyopts(fd->rfd, popts, PH_LATE);
+ if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
+ }
+ break;
+
+#if LATER
+ case XIOCOMM_TCP4_LISTEN: {
+ /*!indent*/
+ int pf = AF_INET;
+ xiofd_t socatfd, execfd;
+ retropt_int(popts, OPT_PROTOCOL_FAMILY, &pf);
+ if (xiocommpair(commtype, XIOWITHWR(rw), XIOWITHRD(rw),
+ 0, &socatfd, &execfd) < 0) {
+ return -1;
+ }
+
+ free(*copts);
+ if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
+ return -1;
+ }
+ applyopts_cloexec(ptyfd, popts);/*!*/
+ }
+ break;
+#endif /* LATER */
+
+ case XIOCOMM_SOCKETPAIRS:
+ case XIOCOMM_PTYS: {
+ xiofd_t socatfd, execfd;
+ struct termios andmask, ormask;
+ switch (commtype) {
+ case XIOCOMM_SOCKETPAIRS:
+ if (xiocommpair(commtype, XIOWITHWR(rw), XIOWITHRD(rw),
+ 0, &socatfd, &execfd, PF_UNIX, SOCK_STREAM, 0) < 0)
+ return -1;
+ break;
+ case XIOCOMM_PTYS:
+ if (xiocommpair(commtype, XIOWITHWR(rw), XIOWITHRD(rw),
+ 0, &socatfd, &execfd, &andmask, &ormask) < 0)
+ return -1;
+ break;
+ }
+
+ free(*copts);
+ if ((*copts = copyopts(popts, GROUP_TERMIOS|GROUP_FORK)) == NULL) {
+ return -1;
+ }
+ if (socatfd.rfd >= 0) {
+ applyopts_cloexec(socatfd.rfd, *copts);/*!*/
+ applyopts(socatfd.rfd, *copts, PH_FD);
+ applyopts(socatfd.rfd, *copts, PH_LATE);
+ }
+ if (applyopts_single(xfd, *copts, PH_LATE) < 0) return -1;
+
+ free(*copts);
+ if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
+ return -1;
+ }
+ if (socatfd.wfd >= 0) {
+ applyopts_cloexec(socatfd.wfd, *copts);/*!*/
+ applyopts(socatfd.wfd, *copts, PH_FD);
+ applyopts(socatfd.wfd, *copts, PH_LATE);
+ }
+ if (applyopts_single(xfd, *copts, PH_LATE) < 0) return -1;
+
+ if (XIOWITHRD(rw)) xfd->rfd = socatfd.rfd;
+ if (XIOWITHWR(rw)) xfd->wfd = socatfd.wfd;
+ xfd->dtype = socatfd.dtype;
+ if (xfd->howtoshut == XIOSHUT_UNSPEC)
+ xfd->howtoshut = socatfd.howtoshut;
+ if (fd->howtoclose == XIOCLOSE_UNSPEC) {
+ fd->howtoclose = XIOWITHRD(rw)?XIOCLOSE_CLOSE_SIGTERM:XIOCLOSE_SLEEP_SIGTERM;
+ }
+ wrpip[0] = execfd.rfd;
+ rdpip[1] = execfd.wfd;
+ rdpip[0] = socatfd.rfd;
+ wrpip[1] = socatfd.wfd;
+ }
+ break;
+
+ default:
+ Error1("_xioopen_progcall() internal: commtype %d not handled",
+ commtype);
+ break;
+ }
+
/*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL)
return -1;*/
retropt_bool(*copts, OPT_STDERR, &withstderr);
@@ -1127,8 +646,11 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
Warn1("signal(SIGCHLD, SIG_IGN): %s", strerror(errno));
}
+ /* dup2() the fds to desired values, close old fds, and apply late
+ options */
+ switch (commtype) {
#if HAVE_PTY
- if (usepty) {
+ case XIOCOMM_PTY:
if (rw != XIO_RDONLY && fdi != ttyfd) {
if (Dup2(ttyfd, fdi) < 0) {
Error3("dup2(%d, %d): %s", ttyfd, fdi, strerror(errno));
@@ -1147,18 +669,27 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
}
applyopts(ttyfd, *copts, PH_LATE);
-
applyopts(ttyfd, *copts, PH_LATE2);
- } else
+ break;
#endif /* HAVE_PTY */
- if (usepipes) {
+
+ case XIOCOMM_PIPES:
+ case XIOCOMM_SOCKETPAIRS:
+ case XIOCOMM_PTYS:
+ {
+ /*!indent*/
/* we might have a temporary conflict between what FDs are
currently allocated, and which are to be used. We try to find
a graceful solution via temporary descriptors */
int tmpi, tmpo;
- Close(rdpip[0]);
- Close(wrpip[1]);
+ /* needed with system() (not with exec()) */
+ if (XIOWITHRD(rw)) Close(rdpip[0]);
+ if (XIOWITHWR(rw)) Close(wrpip[1]);
+#if 0
+ /*! might not be needed */
+ if (XIOWITHRD(rw)) Close(rdpip[0]);
+ if (XIOWITHWR(rw)) Close(wrpip[1]);
if (fdi == rdpip[1]) { /* a conflict here */
if ((tmpi = Dup(wrpip[0])) < 0) {
@@ -1196,13 +727,23 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
/*0 applyopts_cloexec(wrpip[0], *copts);*/ /* option is already consumed! */
/* applyopts_cloexec(fdi, *copts);*/ /* option is already consumed! */
}
-
+#else
+ result = reassignfds(XIOWITHWR(rw)?wrpip[0]:-1,
+ XIOWITHRD(rw)?rdpip[1]:-1,
+ fdi, fdo);
+ if (result < 0) return result;
+#endif
applyopts(fdi, *copts, PH_LATE);
applyopts(fdo, *copts, PH_LATE);
applyopts(fdi, *copts, PH_LATE2);
applyopts(fdo, *copts, PH_LATE2);
-
- } else { /* socketpair */
+ break;
+ }
+ case XIOCOMM_SOCKETPAIR:
+ case XIOCOMM_TCP:
+ case XIOCOMM_TCP4:
+ case XIOCOMM_TCP4_LISTEN:
+ /*!indent*/
if (rw != XIO_RDONLY && fdi != sv[1]) {
if (Dup2(sv[1], fdi) < 0) {
Error3("dup2(%d, %d): %s", sv[1], fdi, strerror(errno));
@@ -1221,9 +762,32 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
applyopts(fdi, *copts, PH_LATE);
applyopts(fdi, *copts, PH_LATE2);
+ Close(sv[1]);
+ break;
+
+ default:
+ Error1("_xioopen_progcall() internal: commtype %d not handled",
+ commtype);
+ break;
+
+ }
+
+ /* in case of an inter address, assign the right side FDs (e.g. 3 and 4) */
+ if (inter) {
+ Info2("preparing the right side FDs %d and %d for exec process",
+ rightin, rightout);
+ result = reassignfds(XIOWITHRD(rw)?saverfd:-1,
+ XIOWITHWR(rw)?savewfd:-1,
+ rightin, form==2?rightout:STDOUT_FILENO);
+ if (result < 0) return result;
+ if (form == 2) {
+ Fcntl_l(rightin, F_SETFD, 0);
+ Fcntl_l(rightout, F_SETFD, 0);
}
+ }
+
} /* withfork */
- else {
+ else /* !withfork */ {
applyopts(-1, *copts, PH_LATE);
applyopts(-1, *copts, PH_LATE2);
}
@@ -1253,22 +817,28 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
return STAT_RETRYLATER;
#endif
- if (0) {
- ; /* for canonical reasons */
+ /* in parent: close fds that are only needed in child */
+ switch (commtype) {
#if HAVE_PTY
- } else if (usepty) {
+ case XIOCOMM_PTY:
if (Close(ttyfd) < 0) {
Info2("close(%d): %s", ttyfd, strerror(errno));
}
+ break;
#endif /* HAVE_PTY */
-#if 1
- } else if (usepipes) {
- Close(wrpip[0]);
- Close(rdpip[1]);
- } else { /* socketpair() */
+ case XIOCOMM_SOCKETPAIR:
+ case XIOCOMM_TCP:
+ case XIOCOMM_TCP4:
+ case XIOCOMM_TCP4_LISTEN:
Close(sv[1]);
+ break;
+ case XIOCOMM_PIPES:
+ default:
+ if (XIOWITHWR(rw)) Close(wrpip[0]);
+ if (XIOWITHRD(rw)) Close(rdpip[1]);
+ break;
}
-#endif
+
fd->child.pid = pid;
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
@@ -1279,6 +849,11 @@ int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
return STAT_NORETRY;
}
+ if (inter) {
+ if (XIOWITHRD(rw)) Close(saverfd);
+ if (XIOWITHWR(rw)) Close(savewfd);
+ }
+
return pid; /* indicate parent (main) process */
}
@@ -1294,3 +869,78 @@ int setopt_path(struct opt *opts, char **path) {
}
return 0;
}
+
+
+/* like dup(), but prints error on failure */
+static int xiodup(int oldfd) {
+ int result;
+ if ((result = Dup(oldfd)) >= 0) return result;
+ Error2("dup2(%d): %s", oldfd, strerror(errno));
+ return result;
+}
+
+/* like dup2(), but prints error on failure and returns 0 on success */
+static int xiodup2(int oldfd, int newfd) {
+ int result;
+ if ((result = Dup2(oldfd, newfd)) >= 0) return 0;
+ Error3("dup2(%d, %d): %s", oldfd, newfd, strerror(errno));
+ return result;
+}
+
+/* move the filedescriptors from the old handles to the new handles.
+ old -1 handles are ignored, new -1 handles are not closed.
+ returns 0 on success, -1 if a dup error occurred, or 1 on a close error
+*/
+static int reassignfds(int oldfd1, int oldfd2, int newfd1, int newfd2) {
+ int tmpfd;
+ int result;
+
+ Debug4("reassignfds(%d, %d, %d, %d)", oldfd1, oldfd2, newfd1, newfd2);
+ if (oldfd1 == newfd1) {
+ Fcntl_l(newfd1, F_SETFD, 0);
+ oldfd1 = -1;
+ }
+ if (oldfd2 == newfd2) {
+ Fcntl_l(newfd2, F_SETFD, 0);
+ oldfd2 = -1;
+ }
+
+ if (oldfd1 < 0 && oldfd2 < 0) return 0;
+
+ if (oldfd2 < 0) {
+ if ((result = xiodup2(oldfd1, newfd1)) < 0) return result;
+ if (newfd2 != oldfd1) if (Close(oldfd1) < 0) return 1;
+ return 0;
+ }
+
+ if (oldfd1 < 0) {
+ if ((result = xiodup2(oldfd2, newfd2)) < 0) return result;
+ if (oldfd2 >= 0) if (Close(oldfd2) < 0) return 1;
+ return 0;
+ }
+
+ if (oldfd2 == newfd1) {
+ if (oldfd1 == newfd2) {
+ /* exchange them */
+ if ((tmpfd = xiodup(oldfd2)) < 0) return tmpfd;
+ if ((result = xiodup2(oldfd1, newfd1)) < 0) return result;
+ if ((result = xiodup2(tmpfd, newfd2)) < 0) return result;
+ if (Close(tmpfd) < 0) return 1;
+ } else {
+ if ((result = xiodup2(oldfd2, newfd2)) < 0) return result;
+ if ((result = xiodup2(oldfd1, newfd1)) < 0) return result;
+ if (Close(oldfd1) < 0) return 1;
+ }
+ } else {
+ if (oldfd1 == newfd2) {
+ if ((result = xiodup2(oldfd1, newfd1)) < 0) return result;
+ if ((result = xiodup2(oldfd2, newfd2)) < 0) return result;
+ if (Close(oldfd2) < 0) return 1;
+ } else {
+ if ((result = xiodup2(oldfd1, newfd1)) < 0) return result;
+ if ((result = xiodup2(oldfd2, newfd2)) < 0) return result;
+ if (Close(oldfd1) < 0 || Close(oldfd2) < 0) return 1;
+ }
+ }
+ return 0;
+}
diff --git a/xio-progcall.h b/xio-progcall.h
index 3f42be0..840f942 100644
--- a/xio-progcall.h
+++ b/xio-progcall.h
@@ -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
diff --git a/xio-proxy.c b/xio-proxy.c
index 3153695..4e67fe2 100644
--- a/xio-proxy.c
+++ b/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);
/*! */
diff --git a/xio-pty.c b/xio-pty.c
index 0fae9b3..b7984f1 100644
--- a/xio-pty.c
+++ b/xio-pty.c
@@ -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;
diff --git a/xio-rawip.c b/xio-rawip.c
index 66fb7c8..52389d1 100644
--- a/xio-rawip.c
+++ b/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,
diff --git a/xio-readline.c b/xio-readline.c
index 74f3318..acd6eab 100644
--- a/xio-readline.c
+++ b/xio-readline.c
@@ -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);
diff --git a/xio-socket.c b/xio-socket.c
index 193fca5..eb0bc79 100644
--- a/xio-socket.c
+++ b/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;
}
diff --git a/xio-socks.c b/xio-socks.c
index 82b600d..f8961a2 100644
--- a/xio-socks.c
+++ b/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));
diff --git a/xio-socks5.c b/xio-socks5.c
index 7c0f9e0..7c08862 100644
--- a/xio-socks5.c
+++ b/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 */
}
diff --git a/xio-stdio.c b/xio-stdio.c
index 2528aea..8afc4ac 100644
--- a/xio-stdio.c
+++ b/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 */
diff --git a/xio-system.c b/xio-system.c
index c293d42..772cd76 100644
--- a/xio-system.c
+++ b/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(":") };
+/* 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(":") };
+/* 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(":") };
+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(":") };
+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(":") };
+/* 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(":") };
+/* 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;
diff --git a/xio-system.h b/xio-system.h
index 9a20a8f..e9222eb 100644
--- a/xio-system.h
+++ b/xio-system.h
@@ -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) */
diff --git a/xio-tcpwrap.c b/xio-tcpwrap.c
index d8a03a9..01ad523 100644
--- a/xio-tcpwrap.c
+++ b/xio-tcpwrap.c
@@ -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);
diff --git a/xio-test.c b/xio-test.c
index 1488622..2bc6a30 100644
--- a/xio-test.c
+++ b/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;
diff --git a/xio-tun.c b/xio-tun.c
index 7aa2311..4e07571 100644
--- a/xio-tun.c
+++ b/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;
diff --git a/xio-udp.c b/xio-udp.c
index 2c2bd9a..2c0d6ff 100644
--- a/xio-udp.c
+++ b/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;
}
diff --git a/xio-unix.c b/xio-unix.c
index 40980ab..9877b4f 100644
--- a/xio-unix.c
+++ b/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;
}
diff --git a/xio.h b/xio.h
index a08341e..6d13a10 100644
--- a/xio.h
+++ b/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);
diff --git a/xioclose.c b/xioclose.c
index ede3820..af2d6ec 100644
--- a/xioclose.c
+++ b/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 */
diff --git a/xioengine.c b/xioengine.c
index e967197..86a8608 100644
--- a/xioengine.c
+++ b/xioengine.c
@@ -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 {
diff --git a/xioopen.c b/xioopen.c
index e32341a..3308194 100644
--- a/xioopen.c
+++ b/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(,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 {
diff --git a/xioopts.c b/xioopts.c
index 2497875..2cff2f4 100644
--- a/xioopts.c
+++ b/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);
diff --git a/xioopts.h b/xioopts.h
index 6276cc8..248e685 100644
--- a/xioopts.h
+++ b/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,
diff --git a/xioparam.c b/xioparam.c
index 792f278..5218bd6 100644
--- a/xioparam.c
+++ b/xioparam.c
@@ -32,6 +32,7 @@ xioopts_t xioopts = {
{0,500000}, /* closwait */
false, /* lefttoright */
false, /* righttoleft */
+ 0, /* pipetype: two unidirectional socketpairs */
} ;
xioopts_t *xioparams = &xioopts;
diff --git a/xioread.c b/xioread.c
index 7c5dc28..476070f 100644
--- a/xioread.c
+++ b/xioread.c
@@ -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);
diff --git a/xioshutdown.c b/xioshutdown.c
index 49c7f82..282de50 100644
--- a/xioshutdown.c
+++ b/xioshutdown.c
@@ -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;
diff --git a/xiosocketpair.c b/xiosocketpair.c
index 5ce69b3..c12fcf3 100644
--- a/xiosocketpair.c
+++ b/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;
}