From 515c305a7fa83c1348c6058d8fdadae4f7609f75 Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Fri, 3 Apr 2009 11:30:01 +0200 Subject: [PATCH] added inter address exec and system modules --- Makefile.in | 13 +- VERSION | 2 +- bin/cat2.sh | 68 ++ bin/predialog.sh | 53 ++ doc/socat-addresschain.html | 320 +++++++++ doc/socat-exec.html | 114 ++++ doc/socat.yo | 385 ++++++----- proxyecho.sh | 4 +- socat.c | 21 +- sycls.c | 4 +- test.sh | 334 ++++++++-- xio-creat.c | 27 +- xio-exec.c | 38 +- xio-exec.h | 3 +- xio-fd.c | 8 +- xio-fd.h | 2 + xio-fdnum.c | 62 +- xio-file.c | 33 +- xio-gopen.c | 60 +- xio-interface.c | 14 +- xio-ipapp.c | 5 +- xio-listen.c | 62 +- xio-nop.c | 4 +- xio-openssl.c | 183 +++--- xio-pipe.c | 21 +- xio-progcall.c | 1218 +++++++++++++---------------------- xio-progcall.h | 32 +- xio-proxy.c | 45 +- xio-pty.c | 5 +- xio-rawip.c | 18 +- xio-readline.c | 49 +- xio-socket.c | 204 +++--- xio-socks.c | 39 +- xio-socks5.c | 64 +- xio-stdio.c | 48 +- xio-system.c | 30 +- xio-system.h | 3 +- xio-tcpwrap.c | 6 +- xio-test.c | 26 +- xio-tun.c | 19 +- xio-udp.c | 71 +- xio-unix.c | 26 +- xio.h | 59 +- xioclose.c | 25 +- xioengine.c | 4 +- xioopen.c | 275 +++++--- xioopts.c | 48 +- xioopts.h | 13 +- xioparam.c | 1 + xioread.c | 4 +- xioshutdown.c | 45 +- xiosocketpair.c | 514 ++++++++++----- 52 files changed, 2887 insertions(+), 1844 deletions(-) create mode 100755 bin/cat2.sh create mode 100755 bin/predialog.sh create mode 100644 doc/socat-addresschain.html create mode 100644 doc/socat-exec.html diff --git a/Makefile.in b/Makefile.in index 12c9b32..f319a62 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,5 +1,5 @@ # source: Makefile.in -# Copyright Gerhard Rieger 2001-2008 +# Copyright Gerhard Rieger 2001-2009 # Published under the GNU General Public License V.2, see file COPYING # note: @...@ forms are filled in by configure script @@ -73,10 +73,17 @@ HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes. xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h xio-tun.h \ xiosigchld.h xiostatic.h xio-nop.h xio-test.h -DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT doc/socat.yo doc/socat.1 doc/socat.html doc/xio.help FAQ BUGREPORTS COPYING COPYING.OpenSSL doc/dest-unreach.css doc/socat-openssltunnel.html doc/socat-multicast.html doc/socat-tun.html doc/socat-genericsocket.html +DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY \ + DEVELOPMENT doc/socat.yo doc/socat.1 doc/socat.html doc/xio.help FAQ \ + BUGREPORTS COPYING COPYING.OpenSSL doc/dest-unreach.css \ + doc/socat-openssltunnel.html doc/socat-multicast.html \ + doc/socat-tun.html doc/socat-genericsocket.html \ + doc/socat-addresschain.html doc/socat-exec.html SHFILES = daemon.sh mail.sh ftp.sh readline.sh TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \ - proxy.sh socks4a-echo.sh testcert.conf + proxy.sh socks4a-echo.sh bin/cat2.sh bin/predialog.sh \ + bin/cat2.sh bin/predialog.sh \ + testcert.conf OSFILES = Config/Makefile.Linux-2-6-24 Config/config.Linux-2-6-24.h \ Config/Makefile.SunOS-5-10 Config/config.SunOS-5-10.h \ Config/Makefile.FreeBSD-6-1 Config/config.FreeBSD-6-1.h \ diff --git a/VERSION b/VERSION index 35fad60..b5f2dca 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -"2.0.0-b2" +"2+exec" diff --git a/bin/cat2.sh b/bin/cat2.sh new file mode 100755 index 0000000..d2747d4 --- /dev/null +++ b/bin/cat2.sh @@ -0,0 +1,68 @@ +#! /bin/bash +# source: cat2.sh +# Copyright Gerhard Rieger 2009 +# Published under the GNU General Public License V.2, see file COPYING + +# This is an example script that shows how to write a script for use with socat +# intermediate addresses. it shows a simple case consisting of two +# unidirectional programs. +# note how the n>&- and n<&- controls are used to close FDs on sub processes +# to make half close possible. + +# uncomment this if you want to analyse which file descriptors are open +#filan -s -o+2; sleep 1; echo + +# these are the "right side" file descriptors provided by socat; 0 and 1 are +# the "left side" FDs +RINFD=3 +ROUTFD=4 + +if true; then + + # this is a typical example. + #these work fine + socat -u - - <&3 3<&- 4>&- & # right (3) to left (1) + socat -u - - <&0 >&4 4>&- 3<&- & # left (0) to right (4) + #strace -o /tmp/cat.strace -v -tt -f -F -x -s 1024 cat <&3 3<&- 4>&- & # right (3) to left (1) + #cat <&0 1>&- >&4 4>&- 3<&- & # left (0) to right (4) + exec 1>&- 4>&- + exec 0<&- 3<&- + +elif false; then + + # works except close in reverse direction + cat <&3 3<&- 4>&- & # right (3) to left (1) + exec cat <&0 1>&- >&4 4>&- 3<&- # left (0) to right (4) + +elif true; then + + # works - forw, rev + #socat $SOCAT_OPTS -u fd:$RINFD - &- & # right to left + #socat $SOCAT_OPTS -u - fd:$ROUTFD >/dev/null 3<&- & # left to right + exec 1>&- 4>&- + exec 0<&- 3<&- + +elif false; then + + # works - forw, rev + socat -u - - <&3 3<&- 4>&- & # right (3) to left (1) + exec socat -u - - <&0 1>&- >&4 4>&- 3<&- # left (0) to right (4) + +else + + # works except close in reverse + #filan -s -o+2 <&3 3<&- 4>&- & # right (3) to left (1) + cat <&3 3<&- 4>&- & # right (3) to left (1) + #socat -d -d -d -d -u - - <&3 3<&- 4>&- & # right (3) to left (1) + + #sleep 1; echo >&2; filan -s -o+2 <&0 >&4 4>&- 3<&- & # left (0) to right (4) + #cat <&0 >&4 4>&- 3<&- & # left (0) to right (4) + socat -u - - <&0 >&4 4>&- 3<&- & # left (0) to right (4) + + exec 1>&- 4>&- + exec 0<&- 3<&- + #sleep 1; echo >&2; filan -s -o+2 + +fi + +wait diff --git a/bin/predialog.sh b/bin/predialog.sh new file mode 100755 index 0000000..d0ba39f --- /dev/null +++ b/bin/predialog.sh @@ -0,0 +1,53 @@ +#! /bin/bash +# source: predialog.sh +# Copyright Gerhard Rieger 2009 +# Published under the GNU General Public License V.2, see file COPYING + +# This is an example script that shows how to write a script for use with socat +# intermediate addresses. it shows a case where an initial dialog on the right +# side is performed. afterwards data is just passed in both directions. + +# uncomment this if you want to analyse which file descriptors are open +#filan -s -o+2; sleep 1; echo + +# these are the "right side" file descriptors provided by socat; 0 and 1 are +# the "left side" FDs +RINFD=3 +ROUTFD=4 + +verbose= +# parse options +SPACES=" " +while [ -n "$1" ]; do + case "$1" in + -v) verbose=1 ;; + *) echo "$0: unknown option \"$1\"" >&2; exit -1 ;; + esac + shift +done + +msg () { + [ "$verbose" ] && echo "$0: $1" >&2 +} + +# send a request +msg "sending request" +echo -e "CONNECT 10.0.0.1:80 HTTP/1.0\n" >&4 + +# read reply +msg "waiting for reply" +read -r <&3 +case "$REPLY" in + "HTTP/1.0 200 OK") ;; + *) msg "bad reply \"$REPLY\"" exit 1 ;; +esac +# skip headers until empty line +msg "skipping reply headers" +while read -r <&3 && ! [ "$REPLY" = "" ]; do :; done + +wait + +msg "starting data transfer" +# now just pass traffic in both directions +#SOCAT_OPTS="-lu -d -d -d -d" +exec socat $SOCAT_OPTS - "fd:$ROUTFD:$RINFD" diff --git a/doc/socat-addresschain.html b/doc/socat-addresschain.html new file mode 100644 index 0000000..8f8b0d5 --- /dev/null +++ b/doc/socat-addresschain.html @@ -0,0 +1,320 @@ + + + +Socat address chains + + + + + +

Socat address chains

+ + +

Introduction

+

Socat version 2 can concatenate multiple modules and transfer data between + them bidirectionally. +

+ + + +

Example 1: OpenSSL via HTTP proxy

+ + +socat - "OPENSSL,verify=0 | PROXY:secure.domain.com:443 | TCP:proxy.domain.com:8080" + + +

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

+ + +
+

Address chain basics

+ +

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: +

+ +socat -h |egrep 'b ..b groups=' +

A full socat 2.0.0-b3 program provides the following inter addresses: +

+ + + + + + + + + + + + + +
namedescription
NOPtransfers data unmodified
OPENSSL-CLIENTperforms OpenSSL client negotiation, then + encrypts/decrypts data
OPENSSL-SERVERperforms OpenSSL server negotiation, then + encrypts/decrypts data
PROXYperforms proxy CONNECT client negotiation, then + transfers data unmodified
SOCKS4performs socks 4 client negotiation, then + transfers data unmodified
SOCKS4Aperforms socks 4a client negotiation, then + transfers data unmodified
SOCKS5performs socks 5 TCP client negotiation, then + transfers data unmodified
TESTappends > to forward, and < to reversely + transferred blocks
EXECinvokes a program + (see socat-exec.html), then transfers data unmodified
SYSTEMinvokes the shell (see socat-exec.html), then transfers data unmodified
+ + +
+

Reverse address use

+ +

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

+ + +
+

Example 2:

+ +

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: +

+ +socat TCP-LISTEN:443,reuseaddr,fork "^OPENSSL-SERVER,cert=server.pem | TCP:somehost:80" + + +

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

+ + +
+

Unidirectional data transfer

+ +

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:

+ +socat -h |egrep 'openssl-server' +

gives the following output: +

+

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

+ + +

Dual inter addresses

+ +

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 +

+ + + +

fork

+ +

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

+ + +
+

Understanding chain implementation

+ +

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

Communication types

+ +

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.typehalf close with close()allows shutdownavoids bufferingTCP/IPv4
socketpairsOKOKnono
socketpairnoOKnono
pipesOKnonono
ptysOKnoyesno
tcpnoyesnoyes
+ +

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 2009
+License: GNU Free Documentation License (FDL) +

+ + + diff --git a/doc/socat-exec.html b/doc/socat-exec.html new file mode 100644 index 0000000..cc2b347 --- /dev/null +++ b/doc/socat-exec.html @@ -0,0 +1,114 @@ + + + +Executing programs using socat + + + + + +

Executing programs using socat

+ +

Introduction

+

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

+ +

Program context types

+ +

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

+ +

Executing programs in bidirectional inter address context

+

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: +

+ +

Using unidirectional inter addresses

+

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

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