mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 23:42:34 +00:00
version 2.0.0-b1
This commit is contained in:
parent
b819572f5e
commit
db717446a4
96 changed files with 6419 additions and 2363 deletions
28
CHANGES
28
CHANGES
|
@ -1,4 +1,32 @@
|
|||
|
||||
####################### V 2.0.0-b1:
|
||||
|
||||
new features:
|
||||
address chains consisting of inter and endpoint addresses, linked with
|
||||
'|' (pipe character)
|
||||
|
||||
reverting inter addresses
|
||||
|
||||
dual type inter addresses
|
||||
|
||||
changed form of dual addresses from in!!out to out%in
|
||||
|
||||
address overloading per parameter number, inter/endpoint type, and
|
||||
supported transfer directions
|
||||
|
||||
derived new inter addresses OPENSSL-CLIENT, OPENSSL-SERVER,
|
||||
PROXY-CLIENT, SOCKS4-CLIENT, SOCKS4A-CLIENT from related old addresses
|
||||
|
||||
new inter address SOCKS5-CLIENT
|
||||
|
||||
new inter address NOP
|
||||
|
||||
new inter address TEST, TESTUNI, TESTREV
|
||||
|
||||
new form of PTY address with symlink paramater
|
||||
|
||||
new form of FD address with output/input fd numbers
|
||||
|
||||
####################### V 1.6.0.0:
|
||||
|
||||
new features:
|
||||
|
|
20
EXAMPLES
20
EXAMPLES
|
@ -87,7 +87,7 @@ $ socat -u -,cr -
|
|||
|
||||
// save piped data similar to 'tee':
|
||||
// copies stdin to stdout, but writes everything to the file too
|
||||
$ socat -,echo=0 open:/tmp/myfile,create,trunc,ignoreeof!!/tmp/myfile
|
||||
$ socat - OPEN:/tmp/myfile,create,trunc%open:/tmp/myfile,ignoreeof
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// intrusion testing
|
||||
|
@ -113,23 +113,23 @@ $ socat -,echo=0 open:/tmp/myfile,create,trunc,ignoreeof!!/tmp/myfile
|
|||
// forms of stdin with stdout, all equivalent
|
||||
$ socat echo -
|
||||
$ socat echo STDIO
|
||||
$ socat echo STDIN!!STDOUT
|
||||
$ socat echo STDIO!!STDIO
|
||||
$ socat echo -!!-
|
||||
$ socat echo FD:0!!FD:1
|
||||
$ socat echo 0!!1
|
||||
$ socat echo /dev/stdin!!/dev/stdout // if your OS provides these
|
||||
$ socat echo STDOUT%STDIN
|
||||
$ socat echo STDIO%STDIO
|
||||
$ socat echo -%-
|
||||
$ socat echo FD:1%FD:0
|
||||
$ socat echo 1%0
|
||||
$ socat echo /dev/stdout%/dev/stdin // if your OS provides these
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// some echo address examples
|
||||
$ socat - PIPE
|
||||
$ socat - PIPE:/tmp/pipi // other version of echo
|
||||
$ socat - PIPE:/tmp/pipi,nonblock!!/tmp/pipi // other version of echo
|
||||
$ socat - PIPE:/tmp/pipi%/tmp/pipi // other version of echo
|
||||
$ socat - EXEC:/bin/cat // another echo
|
||||
$ socat - SYSTEM:/bin/cat // another echo
|
||||
$ socat - TCP:loopback:7 // if inetd echo/TCP service activated
|
||||
$ socat - UDP:loopback:7 // if inetd echo/UDP service activated
|
||||
$ socat - /tmp/hugo,trunc,ignoreeof!!/tmp/hugo // with delay
|
||||
$ socat - /tmp/hugo,trunc%/tmp/hugo,ignoreeof // with delay
|
||||
$ socat - UDP:loopback:2000,bind=:2000 // self "connection"
|
||||
$ socat - TCP:loopback:2000,bind=:2000 // Linux bug?
|
||||
# socat - IP:loopback:222 // raw protocol, self "connected" (attention,
|
||||
|
@ -151,7 +151,7 @@ $ socat -u - CREATE:/tmp/outfile1,group=floppy,perm=0640
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// file handling
|
||||
$ socat - FILE:/tmp/outfile1,ignoreeof!!FILE:/tmp/outfile1,append // prints outfile1, then echoes input and protocols into file (appends to old data)
|
||||
$ socat - FILE:/tmp/outfile1,append%FILE:/tmp/outfile1,ignoreeof // prints outfile1, then echoes input and protocols into file (appends to old data)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// unix socket handling
|
||||
|
|
8
FAQ
8
FAQ
|
@ -57,14 +57,6 @@ But the following OS differences result in errors on non Linux systems:
|
|||
$PATH, and "openssl s_server ..." needs enough entropy to generate a key.
|
||||
|
||||
|
||||
Q: When I specify a dual address (two partial addresses linked with "!!") on
|
||||
the command line, I get some message "event not found", and my shell history
|
||||
has the line truncated. Not even protecting the '!'s with '\' helps.
|
||||
|
||||
A: '!' is appearently used by your shell as history expansion character. Say
|
||||
"set +H" and add this line to your (bash) profile.
|
||||
|
||||
|
||||
Q: On Solaris, socat was built successfully, but when started, it gets killed
|
||||
with something like "ld.so.1: ./socat: fatal: libreadline.so.4: open failed: no
|
||||
such file or directory"
|
||||
|
|
37
Makefile.in
37
Makefile.in
|
@ -37,18 +37,19 @@ INSTALL = @INSTALL@
|
|||
|
||||
#0 CFLAGS = @CFLAGS@ $(CCOPTS) $(DEFS) $(INCLS)
|
||||
CFLAGS = @CFLAGS@ $(CCOPTS) $(DEFS) $(CPPFLAGS)
|
||||
CLIBS = $(LIBS)
|
||||
CLIBS = $(LIBS) -lpthread
|
||||
#CLIBS = $(LIBS) -lm -lefence
|
||||
XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \
|
||||
xiosignal.c xiosigchld.c xioread.c xiowrite.c \
|
||||
xiolayer.c xioshutdown.c xioclose.c xioexit.c \
|
||||
xiosignal.c xiosigchld.c xioread.c xiowrite.c xiotransfer.c xioengine.c \
|
||||
xiolayer.c xioshutdown.c xioclose.c xioexit.c xiosocketpair.c \
|
||||
xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \
|
||||
xio-gopen.c xio-creat.c xio-file.c xio-named.c \
|
||||
xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-proxy.c xio-udp.c \
|
||||
xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-socks5.c xio-proxy.c xio-udp.c \
|
||||
xio-rawip.c \
|
||||
xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \
|
||||
xio-pty.c xio-openssl.c \
|
||||
xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c xio-tun.c
|
||||
xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c xio-tun.c \
|
||||
xio-nop.c xio-test.c
|
||||
XIOOBJS = $(XIOSRCS:.c=.o)
|
||||
UTLSRCS = error.c dalan.c procan.c hostan.c fdname.c sysutils.c utils.c nestlex.c @FILAN@ @SYCLS@ @SSLCLS@
|
||||
UTLOBJS = $(UTLSRCS:.c=.o)
|
||||
|
@ -61,24 +62,24 @@ HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.
|
|||
xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \
|
||||
xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \
|
||||
xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \
|
||||
xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \
|
||||
xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-socks5.h xio-proxy.h xio-progcall.h xio-exec.h \
|
||||
xio-system.h xio-termios.h xio-readline.h \
|
||||
xio-pty.h xio-openssl.h \
|
||||
xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h xio-tun.h
|
||||
xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h xio-tun.h \
|
||||
xiosigchld.h xiostatic.h xio-nop.h xio-test.h
|
||||
|
||||
|
||||
DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT doc/socat.1 doc/socat.html doc/xio.help FAQ BUGREPORTS COPYING COPYING.OpenSSL doc/dest-unreach.css doc/socat-openssltunnel.html doc/socat-multicast.html doc/socat-tun.html
|
||||
DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT doc/socat.1 doc/socat.html FAQ BUGREPORTS COPYING COPYING.OpenSSL doc/dest-unreach.css doc/socat-openssltunnel.html doc/socat-multicast.html doc/socat-tun.html
|
||||
SHFILES = daemon.sh mail.sh ftp.sh readline.sh
|
||||
TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \
|
||||
proxy.sh socks4a-echo.sh testcert.conf
|
||||
OSFILES = Config/Makefile.Linux-2-6-16 Config/config.Linux-2-6-16.h \
|
||||
Config/Makefile.AIX-5-1 Config/config.AIX-5-1.h \
|
||||
Config/Makefile.SunOS-5-8 Config/config.SunOS-5-8.h \
|
||||
Config/Makefile.HP-UX-B-11-11 Config/config.HP-UX-B-11-11.h \
|
||||
Config/Makefile.FreeBSD-6-1 Config/config.FreeBSD-6-1.h \
|
||||
Config/Makefile.NetBSD-2-0-2 Config/config.NetBSD-2-0-2.h \
|
||||
Config/Makefile.OpenBSD-3-8 Config/config.OpenBSD-3-8.h \
|
||||
Config/Makefile.Tru64-5-1B Config/config.Tru64-5-1B.h
|
||||
#OSFILES = Config/Makefile.Linux-2-6-16 Config/config.Linux-2-6-16.h \
|
||||
# Config/Makefile.AIX-5-1 Config/config.AIX-5-1.h \
|
||||
# Config/Makefile.SunOS-5-8 Config/config.SunOS-5-8.h \
|
||||
# Config/Makefile.HP-UX-B-11-11 Config/config.HP-UX-B-11-11.h \
|
||||
# Config/Makefile.FreeBSD-6-1 Config/config.FreeBSD-6-1.h \
|
||||
# Config/Makefile.NetBSD-2-0-2 Config/config.NetBSD-2-0-2.h \
|
||||
# Config/Makefile.OpenBSD-3-8 Config/config.OpenBSD-3-8.h \
|
||||
# Config/Makefile.Tru64-5-1B Config/config.Tru64-5-1B.h
|
||||
|
||||
|
||||
all: progs
|
||||
|
@ -133,7 +134,7 @@ socat.tar.bz2: socat.tar
|
|||
|
||||
VERSION = `sed 's/"//g' VERSION`
|
||||
TARDIR = socat-$(VERSION)
|
||||
socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(OSFILES) $(TESTFILES) socat.spec
|
||||
socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(OSFILES) $(TESTFILES)
|
||||
if [ ! -d $(TARDIR) ]; then mkdir $(TARDIR); fi
|
||||
tar cf - $+ |(cd $(TARDIR); tar xf -)
|
||||
tar cvf socat.tar $(TARDIR)
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
"1.6.0.0"
|
||||
"2.0.0-b1"
|
||||
|
|
4
compat.h
4
compat.h
|
@ -1,5 +1,5 @@
|
|||
/* $Id: compat.h,v 1.32 2006/06/19 20:28:52 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __compat_h_included
|
||||
|
@ -587,6 +587,8 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#define F_thread "%lu"
|
||||
|
||||
/* Cygwin 1.3.22 has the prototypes, but not the type... */
|
||||
#ifndef HAVE_TYPE_STAT64
|
||||
# undef HAVE_STAT64
|
||||
|
|
|
@ -444,6 +444,8 @@
|
|||
#undef HAVE_PROC_DIR_FD
|
||||
|
||||
#undef WITH_HELP
|
||||
#undef WITH_NOP
|
||||
#undef WITH_TEST
|
||||
#undef WITH_STDIO
|
||||
#undef WITH_FDNUM
|
||||
#undef WITH_FILE
|
||||
|
@ -461,6 +463,8 @@
|
|||
#undef WITH_LISTEN
|
||||
#undef WITH_SOCKS4
|
||||
#undef WITH_SOCKS4A
|
||||
#define WITH_SOCKS5 1
|
||||
#define WITH_SOCKS4_SERVER 1
|
||||
#undef WITH_PROXY
|
||||
#undef WITH_EXEC
|
||||
#undef WITH_SYSTEM
|
||||
|
|
16
configure.in
16
configure.in
|
@ -90,6 +90,22 @@ AC_ARG_ENABLE(help, [ --disable-help disable help],
|
|||
esac],
|
||||
[AC_DEFINE(WITH_HELP) AC_MSG_RESULT(yes)])
|
||||
|
||||
AC_MSG_CHECKING(whether to include nop address support)
|
||||
AC_ARG_ENABLE(nop, [ --disable-nop disable nop support],
|
||||
[case "$enableval" in
|
||||
no) AC_MSG_RESULT(no);;
|
||||
*) AC_DEFINE(WITH_NOP) AC_MSG_RESULT(yes);;
|
||||
esac],
|
||||
[AC_DEFINE(WITH_NOP) AC_MSG_RESULT(yes)])
|
||||
|
||||
AC_MSG_CHECKING(whether to include test address support)
|
||||
AC_ARG_ENABLE(test, [ --disable-test disable test support],
|
||||
[case "$enableval" in
|
||||
no) AC_MSG_RESULT(no);;
|
||||
*) AC_DEFINE(WITH_TEST) AC_MSG_RESULT(yes);;
|
||||
esac],
|
||||
[AC_DEFINE(WITH_TEST) AC_MSG_RESULT(yes)])
|
||||
|
||||
AC_MSG_CHECKING(whether to include STDIO support)
|
||||
AC_ARG_ENABLE(stdio, [ --disable-stdio disable STDIO support],
|
||||
[case "$enableval" in
|
||||
|
|
489
doc/socat.1
489
doc/socat.1
|
@ -1,11 +1,17 @@
|
|||
.TH "socat" "1" "March 2007" "socat" ""
|
||||
.TH "socat" "1" "July 2006" "socat" ""
|
||||
.PP
|
||||
.PP
|
||||
.SH "NAME"
|
||||
socat \- Multipurpose relay (SOcket CAT)
|
||||
.PP
|
||||
.SH "SYNOPSIS"
|
||||
\f(CWsocat [options] <address> <address>\fP
|
||||
\f(CWsocat [options] <right-address>\fP
|
||||
.br
|
||||
\f(CWsocat [options] <left-address> <right-address>\fP
|
||||
.br
|
||||
\f(CWsocat [options] <left-address> <right-address> \&.\&.\fP
|
||||
.br
|
||||
\f(CWsocat [options] <left-addresses> \&.\&. -- <right-address> \&.\&.\fP
|
||||
.br
|
||||
\f(CWsocat -V\fP
|
||||
.br
|
||||
|
@ -142,7 +148,7 @@ nothing has happened for <timeout> [timeval] seconds
|
|||
Useful with protocols like UDP that cannot transfer EOF\&.
|
||||
.IP "\fB\f(CW-u\fP\fP"
|
||||
Uses unidirectional mode\&. The first address is only used for reading, and the
|
||||
second address is only used for writing (example)\&.
|
||||
second address is only used for writing\&.
|
||||
.IP "\fB\f(CW-U\fP\fP"
|
||||
Uses unidirectional mode in reverse direction\&. The first address is only
|
||||
used for writing, and the second address is only used for reading\&.
|
||||
|
@ -252,7 +258,7 @@ path, the \f(CWexecvp()\fP semantics for finding the program via
|
|||
\f(CW$PATH\fP
|
||||
apply\&. After successful program start, \fBsocat\fP writes data to stdin of the
|
||||
process and reads from its stdout using a UNIX domain socket generated by
|
||||
\f(CWsocketpair()\fP per default\&. (example)
|
||||
\f(CWsocketpair()\fP per default\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,EXEC,FORK,TERMIOS
|
||||
.br
|
||||
|
@ -294,7 +300,7 @@ In case of a UNIX domain socket, \fBsocat\fP connects; if connecting fails,
|
|||
If the entry is not a socket, \fBsocat\fP opens it applying the \f(CWO_APPEND\fP
|
||||
flag\&.
|
||||
If it does not exist, it is opened with flag
|
||||
\f(CWO_CREAT\fP as a regular file (example)\&.
|
||||
\f(CWO_CREAT\fP as a regular file\&.
|
||||
.br
|
||||
Option groups: FD,REG,SOCKET,NAMED,OPEN
|
||||
.br
|
||||
|
@ -315,7 +321,9 @@ Option groups: FD,SOCKET,IP4,IP6
|
|||
.br
|
||||
Useful options:
|
||||
pf,
|
||||
ttl
|
||||
ttl,
|
||||
broadcast
|
||||
.br
|
||||
See also:
|
||||
IP4-SENDTO,
|
||||
IP6-SENDTO,
|
||||
|
@ -334,52 +342,6 @@ Like IP-SENDTO, but always uses IPv6\&.
|
|||
Option groups: FD,SOCKET,IP6
|
||||
.br
|
||||
.IP
|
||||
.IP "\fB\f(CWIP-DATAGRAM:<address>:<protocol>\fP\fP"
|
||||
Sends outgoing data to the specified address which may in particular be a
|
||||
broadcast or multicast address\&. Packets arriving on the local socket are
|
||||
checked if their source addresses match
|
||||
eventual RANGE or TCPWRAP
|
||||
options\&. This address type can for example be used for implementing
|
||||
symmetric or asymmetric broadcast or multicast communications\&.
|
||||
.br
|
||||
Option groups: FD, SOCKET,
|
||||
IP4, IP6, RANGE
|
||||
.br
|
||||
Useful options:
|
||||
range,
|
||||
tcpwrap,
|
||||
broadcast,
|
||||
ip-multicast-loop,
|
||||
ip-multicast-ttl,
|
||||
ip-multicast-if,
|
||||
ip-add-membership,
|
||||
ttl,
|
||||
tos,
|
||||
bind,
|
||||
pf
|
||||
.br
|
||||
See also:
|
||||
IP4-DATAGRAM,
|
||||
IP6-DATAGRAM,
|
||||
IP-SENDTO,
|
||||
IP-RECVFROM,
|
||||
IP-RECV,
|
||||
UDP-DATAGRAM
|
||||
.IP "\fB\f(CWIP4-DATAGRAM:<host>:<protocol>\fP\fP"
|
||||
Like IP-DATAGRAM, but always uses IPv4\&.
|
||||
(example)
|
||||
.br
|
||||
Option groups: FD, SOCKET,
|
||||
IP4, RANGE
|
||||
.br
|
||||
.IP "\fB\f(CWIP6-DATAGRAM:<host>:<protocol>\fP\fP"
|
||||
Like IP-DATAGRAM, but always uses IPv6\&. Please
|
||||
note that IPv6 does not know broadcasts\&.
|
||||
.br
|
||||
Option groups: FD, SOCKET,
|
||||
IP6, RANGE
|
||||
.br
|
||||
.IP
|
||||
.IP "\fB\f(CWIP-RECVFROM:<protocol>\fP\fP"
|
||||
Opens a raw IP socket of <protocol>\&. Depending on option pf, IP procotol version
|
||||
4 or 6 is used\&. It receives one packet from an unspecified peer and may send one or more answer packets to that peer\&.
|
||||
|
@ -449,8 +411,7 @@ Option groups: FD,SOCKET,IP6,RANGE
|
|||
.br
|
||||
.IP
|
||||
.IP "\fB\f(CWOPEN:<filename>\fP\fP"
|
||||
Opens <filename> using the \f(CWopen()\fP system call
|
||||
(example)\&.
|
||||
Opens <filename> using the \f(CWopen()\fP system call\&.
|
||||
This operation fails on UNIX domain sockets\&.
|
||||
.br
|
||||
Note: This address type is rarly useful in bidirectional mode\&.
|
||||
|
@ -510,9 +471,11 @@ connection is accepted, this address behaves as SSL server\&.
|
|||
.br
|
||||
Note: You probably want to use the certificate option with this address\&.
|
||||
.br
|
||||
NOTE: The client certificate is only checked for validity against
|
||||
cafile or capath,
|
||||
but not for match with the client\'s name or its IP address!
|
||||
NOTE: Without verify option, the client certificate is
|
||||
not checked\&. Even with verify option, the client
|
||||
certificate is only checked for validity against cafile
|
||||
or capath, but not for match with the client\'s name or
|
||||
its IP address!
|
||||
.br
|
||||
Option groups: FD,SOCKET,IP4,IP6,TCP,LISTEN,OPENSSL,CHILD,RANGE,RETRY
|
||||
.br
|
||||
|
@ -596,11 +559,12 @@ retry
|
|||
.br
|
||||
See also: SOCKS, TCP
|
||||
.IP "\fB\f(CWPTY\fP\fP"
|
||||
.IP "\fB\f(CWPTY:<symlink>\fP\fP"
|
||||
Generates a pseudo terminal (pty) and uses its master side\&. Another process
|
||||
may open the pty\'s slave side using it like a serial line or terminal\&.
|
||||
(example)\&. If
|
||||
may open the pty\'s slave side using it like a serial line or terminal\&. If
|
||||
both the ptmx and the openpty mechanisms are available, ptmx is used
|
||||
(POSIX)\&.
|
||||
(POSIX)\&. In the second form, the link option is
|
||||
already integrated as a parameter\&.
|
||||
.br
|
||||
Option groups: FD,NAMED,PTY,TERMIOS
|
||||
.br
|
||||
|
@ -618,7 +582,7 @@ PIPE,
|
|||
EXEC, SYSTEM
|
||||
.IP "\fB\f(CWREADLINE\fP\fP"
|
||||
Uses GNU readline and history on stdio to allow editing and reusing input
|
||||
lines (example)\&. This requires the GNU readline and
|
||||
lines\&. This requires the GNU readline and
|
||||
history libraries\&. Note that stdio should be a (pseudo) terminal device,
|
||||
otherwise readline does not seem to work\&.
|
||||
.br
|
||||
|
@ -635,7 +599,7 @@ Connects via <socks-server> [IP address]
|
|||
to <host> [IPv4 address]
|
||||
on <port> [TCP service],
|
||||
using socks version 4 protocol over IP version 4 or 6 depending on address specification, name resolution, or option
|
||||
pf (example)\&.
|
||||
pf\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,IP4,IP6,TCP,SOCKS4,RETRY
|
||||
.br
|
||||
|
@ -743,7 +707,7 @@ TCP-LISTEN,
|
|||
UDP,
|
||||
UNIX-CONNECT
|
||||
.IP "\fB\f(CWTCP4:<host>:<port>\fP\fP"
|
||||
Like TCP, but only supports IPv4 protocol (example)\&.
|
||||
Like TCP, but only supports IPv4 protocol\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,IP4,TCP,RETRY
|
||||
.br
|
||||
|
@ -783,7 +747,7 @@ UNIX-LISTEN,
|
|||
OPENSSL-LISTEN
|
||||
.IP "\fB\f(CWTCP4-LISTEN:<port>\fP\fP"
|
||||
Like TCP-LISTEN, but only supports IPv4
|
||||
protocol (example)\&.
|
||||
protocol\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4,TCP,RETRY
|
||||
.br
|
||||
|
@ -796,23 +760,7 @@ ipv6only
|
|||
.br
|
||||
Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6,TCP,RETRY
|
||||
.br
|
||||
.IP "\fB\f(CWTUN:<if-addr>/<bits>\fP\fP"
|
||||
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
|
||||
and write access to the tunnel cloning device, usually \f(CW/dev/net/tun\fP\&.
|
||||
.br
|
||||
Option groups: FD,NAMED,OPEN,TUN
|
||||
.br
|
||||
Useful options:
|
||||
iff-up,
|
||||
tun-device,
|
||||
tun-name,
|
||||
tun-type,
|
||||
iff-no-pi
|
||||
.br
|
||||
See also:
|
||||
ip-recv
|
||||
.IP
|
||||
.IP "\fB\f(CWUDP:<host>:<port>\fP\fP"
|
||||
Connects to <port> [UDP service] on
|
||||
<host> [IP address] using UDP/IP version 4 or 6
|
||||
|
@ -849,60 +797,14 @@ Like UDP, but only supports IPv6 protocol\&.
|
|||
.br
|
||||
Option groups: FD,SOCKET,IP6
|
||||
.br
|
||||
.IP "\fB\f(CWUDP-DATAGRAM:<address>:<port>\fP\fP"
|
||||
Sends outgoing data to the specified address which may in particular be a
|
||||
broadcast or multicast address\&. Packets arriving on the local socket are
|
||||
checked for the correct remote port and if their source addresses match
|
||||
eventual RANGE or TCPWRAP
|
||||
options\&. This address type can for example be used for implementing
|
||||
symmetric or asymmetric broadcast or multicast communications\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,IP4,IP6,RANGE
|
||||
.br
|
||||
Useful options:
|
||||
range,
|
||||
tcpwrap,
|
||||
broadcast,
|
||||
ip-multicast-loop,
|
||||
ip-multicast-ttl,
|
||||
ip-multicast-if,
|
||||
ip-add-membership,
|
||||
ttl,
|
||||
tos,
|
||||
bind,
|
||||
sourceport,
|
||||
pf
|
||||
.br
|
||||
See also:
|
||||
UDP4-DATAGRAM,
|
||||
UDP6-DATAGRAM,
|
||||
UDP-SENDTO,
|
||||
UDP-RECVFROM,
|
||||
UDP-RECV,
|
||||
UDP-CONNECT,
|
||||
UDP-LISTEN,
|
||||
IP-DATAGRAM
|
||||
.IP "\fB\f(CWUDP4-DATAGRAM:<address>:<port>\fP\fP"
|
||||
Like UDP-DATAGRAM, but only supports IPv4
|
||||
protocol (example1,
|
||||
example2)\&.
|
||||
.br
|
||||
Option groups: FD, SOCKET,
|
||||
IP4, RANGE
|
||||
.IP "\fB\f(CWUDP6-DATAGRAM:<address>:<port>\fP\fP"
|
||||
Like UDP-DATAGRAM, but only supports IPv6
|
||||
protocol\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,
|
||||
IP6,RANGE
|
||||
.IP
|
||||
.IP "\fB\f(CWUDP-LISTEN:<port>\fP\fP"
|
||||
Waits for a UDP/IP packet arriving on <port>
|
||||
[UDP service] and `connects\' back to sender\&.
|
||||
The accepted IP version is 4 or the one specified with option
|
||||
pf\&.
|
||||
Please note that,
|
||||
due to UDP protocol properties, no real connection is established; data has
|
||||
to arrive from the peer first, and no end-of-file condition can be
|
||||
due to UDP protocol properties, no real connection is established; data has to arrive from the peer first, and no end-of-file condition can be
|
||||
transported\&. Note that opening
|
||||
this address usually blocks until a client connects\&.
|
||||
.br
|
||||
|
@ -931,14 +833,13 @@ protocol\&.
|
|||
.br
|
||||
Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6
|
||||
.br
|
||||
.IP
|
||||
.IP "\fB\f(CWUDP-SENDTO:<host>:<port>\fP\fP"
|
||||
Communicates with the specified peer socket, defined by <port> [UDP
|
||||
service] on
|
||||
Communicates with the specified peer socket, defined by <port> [UDP service] on
|
||||
<host> [IP address], using UDP/IP version 4 or 6
|
||||
depending on address specification, name resolution, or option
|
||||
pf\&. It sends packets to and receives packets
|
||||
from that peer socket only\&.
|
||||
This address effectively implements a datagram client\&.
|
||||
pf\&. It sends packets to and receives packets from that peer socket only\&.
|
||||
This is effectively a datagram client\&.
|
||||
It works well with socat UDP-RECVFROM and UDP-RECV address peers\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,IP4,IP6
|
||||
|
@ -959,23 +860,19 @@ UDP-CONNECT,
|
|||
UDP-LISTEN,
|
||||
IP-SENDTO
|
||||
.IP "\fB\f(CWUDP4-SENDTO:<host>:<port>\fP\fP"
|
||||
Like UDP-SENDTO, but only supports IPv4
|
||||
protocol\&.
|
||||
Like UDP-SENDTO, but only supports IPv4 protocol\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,IP4
|
||||
.IP "\fB\f(CWUDP6-SENDTO:<host>:<port>\fP\fP"
|
||||
Like UDP-SENDTO, but only supports IPv6
|
||||
protocol\&.
|
||||
Like UDP-SENDTO, but only supports IPv6 protocol\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,IP6
|
||||
.IP
|
||||
.IP "\fB\f(CWUDP-RECVFROM:<port>\fP\fP"
|
||||
Creates a UDP socket on <port> [UDP service] using
|
||||
UDP/IP version 4 or 6
|
||||
Creates a UDP socket on <port> [UDP service] using UDP/IP version 4 or 6
|
||||
depending on option pf\&.
|
||||
It receives one packet from an unspecified peer and may send one or more
|
||||
answer packets to that peer\&. This mode is particularly useful with fork
|
||||
option
|
||||
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 allows a behaviour similar to typical UDP based servers like ntpd
|
||||
or named\&. This address works well with socat SENDTO address peers\&.
|
||||
|
@ -1012,7 +909,8 @@ Option groups: FD,SOCKET,IP6,CHILD,RANGE
|
|||
Creates a UDP socket on <port> [UDP service] using UDP/IP version 4 or 6
|
||||
depending on option pf\&.
|
||||
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\&.
|
||||
No replies are possible\&. It can be, e\&.g\&., addressed by socat UDP-SENDTO address peers\&.
|
||||
This address works well with socat SENDTO address peers; it behaves similar to a syslog server\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,IP4,IP6,RANGE
|
||||
.br
|
||||
|
@ -1050,9 +948,7 @@ if <filename> is not a UNIX domain socket, this is an error;
|
|||
if <filename> is a UNIX domain socket, but no process is listening, this is
|
||||
an error\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,
|
||||
NAMED,RETRY,
|
||||
UNIX
|
||||
Option groups: FD,SOCKET,NAMED,RETRY
|
||||
.br
|
||||
)
|
||||
Useful options:
|
||||
|
@ -1071,12 +967,9 @@ If <filename> exists and is a UNIX domain socket, binding to the address
|
|||
fails (use 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
|
||||
this address is closed (but see option unlink-close) (example)\&.
|
||||
this address is closed (but see option unlink-close)\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,
|
||||
NAMED,LISTEN,
|
||||
CHILD,RETRY,
|
||||
UNIX
|
||||
Option groups: FD,SOCKET,NAMED,LISTEN,CHILD,RETRY
|
||||
.br
|
||||
Useful options:
|
||||
fork,
|
||||
|
@ -1097,8 +990,7 @@ Communicates with the specified peer socket, defined by [<filename>] assuming it
|
|||
It sends packets to and receives packets from that peer socket only\&.
|
||||
It works well with socat UNIX-RECVFROM and UNIX-RECV address peers\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,
|
||||
NAMED,UNIX
|
||||
Option groups: FD,SOCKET,NAMED
|
||||
.br
|
||||
Useful options:
|
||||
bind
|
||||
|
@ -1116,9 +1008,7 @@ 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\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,
|
||||
NAMED,CHILD,
|
||||
UNIX
|
||||
Option groups: FD,SOCKET,NAMED,CHILD
|
||||
.br
|
||||
Useful options:
|
||||
fork
|
||||
|
@ -1135,8 +1025,7 @@ Creates a UNIX domain datagram socket [<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\&.
|
||||
It behaves similar to a syslog server\&.
|
||||
Option groups: FD,SOCKET,
|
||||
NAMED,UNIX
|
||||
Option groups: FD,SOCKET,NAMED
|
||||
.br
|
||||
See also:
|
||||
UNIX-SENDTO,
|
||||
|
@ -1145,14 +1034,13 @@ UNIX-LISTEN,
|
|||
UDP-RECV,
|
||||
IP-RECV
|
||||
.IP
|
||||
.IP "\fB\f(CWUNIX-CLIENT:<filename>\fP\fP"
|
||||
.IP "\fB\f(CWUNIX:<filename>\fP\fP"
|
||||
Communicates with the specified peer socket, defined by
|
||||
[<filename>] assuming it is a UNIX domain socket\&.
|
||||
It first tries to connect and, if that fails, assumes it is a datagram
|
||||
socket, thus supporting both types\&.
|
||||
.br
|
||||
Option groups: FD,SOCKET,
|
||||
NAMED,UNIX
|
||||
Option groups: FD,SOCKET,NAMED
|
||||
.br
|
||||
Useful options:
|
||||
bind
|
||||
|
@ -1161,19 +1049,6 @@ See also:
|
|||
UNIX-CONNECT,
|
||||
UNIX-SENDTO,
|
||||
GOPEN
|
||||
.IP
|
||||
.IP "\fB\f(CWABSTRACT-CONNECT:<string>\fP\fP"
|
||||
.IP "\fB\f(CWABSTRACT-LISTEN:<string>\fP\fP"
|
||||
.IP "\fB\f(CWABSTRACT-SENDTO:<string>\fP\fP"
|
||||
.IP "\fB\f(CWABSTRACT-RECVFROM:<string>\fP\fP"
|
||||
.IP "\fB\f(CWABSTRACT-RECV:<string>\fP\fP"
|
||||
.IP "\fB\f(CWABSTRACT-CLIENT:<string>\fP\fP"
|
||||
The ABSTRACT addresses are almost identical to the related UNIX addresses
|
||||
except that they do not address file system based sockets but an alternate
|
||||
UNIX domain address space\&. To archieve this the socket address strings are
|
||||
prefixed with "\e0" internally\&. This feature is available (only?) on Linux\&.
|
||||
Option groups are the same as with the related UNIX addresses, except that
|
||||
the ABSTRACT addresses are not member of the NAMED group\&.
|
||||
.PP
|
||||
.SH "ADDRESS OPTIONS"
|
||||
.PP
|
||||
|
@ -1248,37 +1123,20 @@ internally handles
|
|||
this flag for the fds it controls, so in most cases there will be no need to
|
||||
apply this option\&.
|
||||
.IP "\fB\f(CWsetlk\fP\fP"
|
||||
Tries to set a discretionary write lock to the whole file using the \f(CWfcntl(fd,
|
||||
Tries to set a discretionary lock to the whole file using the \f(CWfcntl(fd,
|
||||
F_SETLK, \&.\&.\&.)\fP system call\&. If the file is already locked, this call results
|
||||
in an error\&.
|
||||
On Linux, when the file permissions for group are "S" (g-x,g+s), and the
|
||||
file system is locally mounted with the "mand" option, the lock is
|
||||
mandatory, i\&.e\&. prevents other processes from opening the file\&.
|
||||
.IP "\fB\f(CWsetlkw\fP\fP"
|
||||
Tries to set a discretionary waiting write lock to the whole file using the
|
||||
Tries to set a discretionary waiting lock to the whole file using the
|
||||
\f(CWfcntl(fd, F_SETLKW, \&.\&.\&.)\fP system call\&. If the file is already locked,
|
||||
this call blocks\&.
|
||||
See option setlk for information about making this
|
||||
lock mandatory\&.
|
||||
.IP "\fB\f(CWsetlk-rd\fP\fP"
|
||||
Tries to set a discretionary read lock to the whole file using the \f(CWfcntl(fd,
|
||||
F_SETLK, \&.\&.\&.)\fP system call\&. If the file is already write locked, this call
|
||||
results in an error\&.
|
||||
See option setlk for information about making this
|
||||
lock mandatory\&.
|
||||
.IP "\fB\f(CWsetlkw-rd\fP\fP"
|
||||
Tries to set a discretionary waiting read lock to the whole file using the
|
||||
\f(CWfcntl(fd, F_SETLKW, \&.\&.\&.)\fP system call\&. If the file is already write
|
||||
locked, this call blocks\&.
|
||||
See option setlk for information about making this
|
||||
lock mandatory\&.
|
||||
.IP "\fB\f(CWflock-ex\fP\fP"
|
||||
Tries to set a blocking exclusive advisory lock to the file using the
|
||||
\f(CWflock(fd, LOCK_EX)\fP system call\&. \fBSocat\fP hangs in this call if the file
|
||||
is locked by another process\&.
|
||||
.IP "\fB\f(CWflock-ex-nb\fP\fP"
|
||||
Tries to set a nonblocking exclusive advisory lock to the file using the
|
||||
\f(CWflock(fd, LOCK_EX|LOCK_NB)\fP system call\&. If the file is already locked,
|
||||
\f(CWflock(fd, LOCK_EX)\fP system call\&. If the file is already locked,
|
||||
this option results in an error\&.
|
||||
.IP "\fB\f(CWflock-sh\fP\fP"
|
||||
Tries to set a blocking shared advisory lock to the file using the
|
||||
|
@ -1291,7 +1149,7 @@ this option results in an error\&.
|
|||
.IP "\fB\f(CWlock\fP\fP"
|
||||
Sets a blocking lock on the file\&. Uses the setlk or flock mechanism
|
||||
depending on availability on the particular platform\&. If both are available,
|
||||
the POSIX variant (setlkw) is used\&.
|
||||
the POSIX variant (setlkw) is selected\&.
|
||||
.IP "\fB\f(CWuser=<user>\fP\fP"
|
||||
Sets the <user> (owner) of the stream\&.
|
||||
If the address is member of the NAMED option group,
|
||||
|
@ -1336,8 +1194,7 @@ This is useful only on file system entries\&.
|
|||
.IP "\fB\f(CWappend=<bool>\fP\fP"
|
||||
Always writes data to the actual end of file\&.
|
||||
If the address is member of the OPEN option group,
|
||||
\fBsocat\fP uses the \f(CWO_APPEND\fP flag with the \f(CWopen()\fP system call
|
||||
(example)\&.
|
||||
\fBsocat\fP uses the \f(CWO_APPEND\fP flag with the \f(CWopen()\fP system call\&.
|
||||
Otherwise, \fBsocat\fP applies the \f(CWfcntl(fd, F_SETFL, O_APPEND)\fP call\&.
|
||||
.IP "\fB\f(CWnonblock=<bool>\fP\fP"
|
||||
Tries to open or use file in nonblocking mode\&. Its only effects are that the
|
||||
|
@ -1362,19 +1219,6 @@ when socat is used as a high volume server or proxy where clients often
|
|||
abort the connection\&.
|
||||
.br
|
||||
This option is experimental\&.
|
||||
.IP "\fB\f(CWend-close\fP\fP"
|
||||
Changes the (address dependent) method of ending a connection to just close
|
||||
the file descriptors\&. This is useful when the connection is to be reused by
|
||||
or shared with other processes (example)\&.
|
||||
.br
|
||||
Normally, socket connections will be ended with \f(CWshutdown(2)\fP which
|
||||
terminates the socket even if it is shared by multiple processes\&.
|
||||
\f(CWclose(2)\fP "unlinks" the socket from the process but keeps it active as
|
||||
long as there are still links from other processes\&.
|
||||
.br
|
||||
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\&.
|
||||
.PP
|
||||
.br
|
||||
.PP
|
||||
|
@ -1432,7 +1276,7 @@ E\&.g\&., option `creat\' sets the \f(CWO_CREAT\fP flag\&.
|
|||
See also options append and
|
||||
nonblock\&.
|
||||
.IP "\fB\f(CWcreat=<bool>\fP\fP"
|
||||
Creates the file if it does not exist (example)\&.
|
||||
Creates the file if it does not exist\&.
|
||||
.IP "\fB\f(CWdsync=<bool>\fP\fP"
|
||||
Blocks \f(CWwrite()\fP calls until metainfo is physically written to media\&.
|
||||
.IP "\fB\f(CWexcl=<bool>\fP\fP"
|
||||
|
@ -1513,7 +1357,7 @@ option FORK,
|
|||
these options apply to the child processes instead of the main socat process\&.
|
||||
.IP "\fB\f(CWchroot=<directory>\fP\fP"
|
||||
Performs a \f(CWchroot()\fP operation to <directory>
|
||||
after processing the address (example)\&. This call might require root privilege\&.
|
||||
after processing the address\&. This call might require root privilege\&.
|
||||
.IP "\fB\f(CWchroot-early=<directory>\fP\fP"
|
||||
Performs a \f(CWchroot()\fP operation to <directory>
|
||||
before opening the address\&. This call might require root privilege\&.
|
||||
|
@ -1531,11 +1375,11 @@ Changes the <user> (owner) of the process before opening
|
|||
the address\&. This call might require root privilege\&.
|
||||
.IP "\fB\f(CWsu=<user>\fP\fP"
|
||||
Changes the <user> (owner) and groups of the process after
|
||||
processing the address (example)\&. This call might require root privilege\&.
|
||||
processing the address\&. This call might require root privilege\&.
|
||||
.IP "\fB\f(CWsu-d=<user>\fP\fP"
|
||||
Short name for \fB\f(CWsubstuser-delayed\fP\fP\&.
|
||||
Changes the <user>
|
||||
(owner) and groups of the process after processing the address (example)\&.
|
||||
(owner) and groups of the process after processing the address\&.
|
||||
The user and his groups are retrieved \fIbefore\fP a possible
|
||||
\f(CWchroot()\fP\&. This call might require root privilege\&.
|
||||
.IP "\fB\f(CWsetpgid=<pid_t>\fP\fP"
|
||||
|
@ -1544,7 +1388,7 @@ Makes the process a member of the specified process group
|
|||
is given, or if the value is 0 or 1, the process becomes leader of a new
|
||||
process group\&.
|
||||
.IP "\fB\f(CWsetsid\fP\fP"
|
||||
Makes the process the leader of a new session (example)\&.
|
||||
Makes the process the leader of a new session\&.
|
||||
.PP
|
||||
.br
|
||||
.PP
|
||||
|
@ -1552,7 +1396,7 @@ Makes the process the leader of a new session (example)\&.
|
|||
.PP
|
||||
These options apply to the readline address type\&.
|
||||
.IP "\fB\f(CWhistory=<filename>\fP\fP"
|
||||
Reads and writes history from/to <filename> (example)\&.
|
||||
Reads and writes history from/to <filename>\&.
|
||||
.IP "\fB\f(CWnoprompt\fP\fP"
|
||||
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
|
||||
|
@ -1566,7 +1410,6 @@ 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\&.
|
||||
(example)
|
||||
.IP "\fB\f(CWprompt=<string>\fP\fP"
|
||||
Passes the string as prompt to the readline function\&. readline prints this
|
||||
prompt when stepping through the history\&. If this string matches a constant
|
||||
|
@ -1586,11 +1429,11 @@ Converts the default line termination character NL (\'\en\', 0x0a) to/from CR
|
|||
(\'\er\', 0x0d) when writing/reading on this channel\&.
|
||||
.IP "\fB\f(CWcrnl\fP\fP"
|
||||
Converts the default line termination character NL (\'\en\', 0x0a) to/from CRNL
|
||||
("\er\en", 0x0d0a) when writing/reading on this channel (example)\&.
|
||||
("\er\en", 0x0d0a) when writing/reading on this channel\&.
|
||||
Note: socat simply strips all CR characters\&.
|
||||
.IP "\fB\f(CWignoreeof\fP\fP"
|
||||
When EOF occurs on this channel, \fBsocat\fP ignores it and tries to read more
|
||||
data (like "tail -f") (example)\&.
|
||||
data (like "tail -f")\&.
|
||||
.IP "\fB\f(CWreadbytes=<bytes>\fP\fP"
|
||||
\fBsocat\fP reads only so many bytes from this address (the address provides
|
||||
only so many bytes for transfer and pretends to be at EOF afterwards)\&.
|
||||
|
@ -1610,7 +1453,7 @@ These options are intended for all kinds of sockets, e\&.g\&. IP or UNIX domain\
|
|||
.IP "\fB\f(CWbind=<sockname>\fP\fP"
|
||||
Binds the socket to the given socket address using the \f(CWbind()\fP system
|
||||
call\&. The form of <sockname> is socket domain dependent:
|
||||
IP4 and IP6 allow the form [hostname|hostaddress][:(service|port)] (example),
|
||||
IP4 and IP6 allow the form [hostname|hostaddress][:(service|port)],
|
||||
UNIX domain sockets require <filename>\&.
|
||||
.IP "\fB\f(CWconnect-timeout=<seconds>\fP\fP"
|
||||
Abort the connection attempt after <seconds> [timeval]
|
||||
|
@ -1653,7 +1496,7 @@ the socket layer will pass the buffered data to \fBsocat\fP\&.
|
|||
Sets the receive timeout [timeval]\&.
|
||||
.IP "\fB\f(CWreuseaddr\fP\fP"
|
||||
Allows other sockets to bind to an address even if parts of it (e\&.g\&. the
|
||||
local port) are already in use by \fBsocat\fP (example)\&.
|
||||
local port) are already in use by \fBsocat\fP\&.
|
||||
.IP "\fB\f(CWsndbuf=<bytes>\fP\fP"
|
||||
Sets the size of the send buffer after the \f(CWsocket()\fP call to
|
||||
<bytes> [int]\&.
|
||||
|
@ -1676,14 +1519,6 @@ something like "ip4" or "ip6"\&.
|
|||
.PP
|
||||
.br
|
||||
.PP
|
||||
\fI\fBUNIX option group\fP\fP
|
||||
.PP
|
||||
These options apply to UNIX domain based addresses\&.
|
||||
.IP "\fB\f(CWunix-tightsocklen=[0|1]\fP\fP"
|
||||
On socket operations, pass a socket address length that does not include the
|
||||
whole \f(CWstruct sockaddr_un\fP record but (besides other components) only
|
||||
the relevant part of the filename or abstract string\&. Default is 1\&.
|
||||
.PP
|
||||
\fI\fBIP4 and IP6 option groups\fP\fP
|
||||
.PP
|
||||
These options can be used with IPv4 and IPv6 based sockets\&.
|
||||
|
@ -1706,26 +1541,6 @@ IP options are defined in RFC 791\&.
|
|||
.IP "\fB\f(CWmtudiscover=<0|1|2>\fP\fP"
|
||||
Takes 0, 1, 2 to never, want, or always use path MTU discover on this
|
||||
socket\&.
|
||||
.IP "\fB\f(CWip-add-membership=<multicast-address:interface-address>\fP\fP"
|
||||
.IP "\fB\f(CWip-add-membership=<multicast-address:interface-name>\fP\fP"
|
||||
.IP "\fB\f(CWip-add-membership=<multicast-address:interface-index>\fP\fP"
|
||||
.IP "\fB\f(CWip-add-membership=<multicast-address:interface-address:interface-name>\fP\fP"
|
||||
.IP "\fB\f(CWip-add-membership=<multicast-address:interface-address:interface-index>\fP\fP"
|
||||
Makes the socket member of the specified multicast group\&. This is currently
|
||||
only implemented for IPv4\&. The option takes the IP address of the multicast
|
||||
group and info about the desired network interface\&. The most common syntax
|
||||
is the first one, while the others are only available on systems that
|
||||
provide \f(CWstruct mreqn\fP (Linux)\&.
|
||||
.br
|
||||
The indices of active network interfaces can be shown using the utility
|
||||
\fBprocan\fP\&.
|
||||
dif(\fB\f(CWip-multicast-if=<hostname>\fP\fP)
|
||||
Specifies hostname or address of the network interface to be used for
|
||||
multicast traffic\&.
|
||||
dif(\fB\f(CWip-multicast-loop=<bool>\fP\fP)
|
||||
Specifies if outgoing multicast traffic should loop back to the interface\&.
|
||||
dif(\fB\f(CWip-multicast-ttl=<byte>\fP\fP)
|
||||
Sets the TTL used for outgoing multicast traffic\&. Default is 1\&.
|
||||
.IP "\fB\f(CWres-debug\fP\fP"
|
||||
.IP "\fB\f(CWres-aaonly\fP\fP"
|
||||
.IP "\fB\f(CWres-usevc\fP\fP"
|
||||
|
@ -1777,8 +1592,7 @@ Sets the time to keep the socket in FIN-WAIT-2 state to <seconds>
|
|||
.IP "\fB\f(CWmss=<bytes>\fP\fP"
|
||||
Sets the MSS (maximum segment size) after the \f(CWsocket()\fP call to <bytes>
|
||||
[int]\&. This
|
||||
value is then proposed to the peer with the SYN or SYN/ACK packet
|
||||
(example)\&.
|
||||
value is then proposed to the peer with the SYN or SYN/ACK packet\&.
|
||||
.IP "\fB\f(CWmss-late=<bytes>\fP\fP"
|
||||
Sets the MSS of the socket after connection has been established to <bytes>
|
||||
[int]\&.
|
||||
|
@ -1829,7 +1643,7 @@ thus can be used with UDP and TCP, client and server addresses\&.
|
|||
For outgoing (client) TCP and UDP connections, it sets the source
|
||||
<port> using an extra \f(CWbind()\fP call\&.
|
||||
With TCP or UDP listen addresses, socat immediately shuts down the
|
||||
connection if the client does not use this sourceport (example)\&.
|
||||
connection if the client does not use this sourceport\&.
|
||||
.IP "\fB\f(CWlowport\fP\fP"
|
||||
Outgoing (client) TCP and UDP connections with this option use
|
||||
an unused random source port between 640 and 1023 incl\&. On UNIX class operating
|
||||
|
@ -1849,7 +1663,7 @@ Overrides the default "socks" service or port 1080 for the socks server
|
|||
port with <TCP service>\&.
|
||||
.IP "\fB\f(CWsocksuser=<user>\fP\fP"
|
||||
Sends the <user> [string] in the username field to the
|
||||
socks server\&. Default is the actual user name ($LOGNAME or $USER) (example)\&.
|
||||
socks server\&. Default is the actual user name ($LOGNAME or $USER)\&.
|
||||
.PP
|
||||
.br
|
||||
.PP
|
||||
|
@ -1877,20 +1691,19 @@ server unencrypted (base64 encoded) and might be sniffed\&.
|
|||
.IP "\fB\f(CWresolve\fP\fP"
|
||||
Per default, socat sends to the proxy a CONNECT request containing the
|
||||
target hostname\&. With this option, socat resolves the hostname locally and
|
||||
sends the IP address\&. Please note that, according to RFC 2396, only name
|
||||
resolution to IPv4 addresses is implemented\&.
|
||||
sends the IP address\&.
|
||||
.PP
|
||||
.br
|
||||
.PP
|
||||
\fI\fBRANGE option group\fP\fP
|
||||
.PP
|
||||
These options check if a connecting client should be granted access\&. They can
|
||||
be applied to listening and receiving network sockets\&. tcp-wrappers options
|
||||
fall into this group\&.
|
||||
These options check if a connecting client is granted access\&. They can be
|
||||
applied to listening and receiving network sockets\&. tcp-wrappers options fall
|
||||
into this group\&.
|
||||
.IP "\fB\f(CWrange=<address-range>\fP\fP"
|
||||
After accepting a connection, tests if the peer is within \fIrange\fP\&. For
|
||||
IPv4 addresses, address-range takes the form address/bits, e\&.g\&.
|
||||
10\&.0\&.0\&.0/8, or address:mask, e\&.g\&. 10\&.0\&.0\&.0:255\&.0\&.0\&.0 (example); for IPv6, it is [ip6-address/bits], e\&.g\&. [::1/128]\&.
|
||||
IPv4 addresses, address-range takes the form ww\&.xx\&.yy\&.zz/bits, e\&.g\&.
|
||||
10\&.0\&.0\&.0/8; for IPv6, it is [ip6-address/bits], e\&.g\&. [::1/128]\&.
|
||||
If the client address does not match, \fBsocat\fP issues a warning and keeps
|
||||
listening/receiving\&.
|
||||
.IP "\fB\f(CWtcpwrap[=<name>]\fP\fP"
|
||||
|
@ -1898,7 +1711,7 @@ Uses Wietse Venema\'s libwrap (tcpd) library to determine
|
|||
if the client is allowed to connect\&. The configuration files are
|
||||
/etc/hosts\&.allow and /etc/hosts\&.deny per default, see "man 5 hosts_access"
|
||||
for more information\&. The optional <name> (type string)
|
||||
is passed to the wrapper functions as daemon process name (example)\&.
|
||||
is passed to the wrapper functions as daemon process name\&.
|
||||
If omitted, the basename of socats invocation (argv[0]) is passed\&.
|
||||
If both tcpwrap and range options are applied to an address, both
|
||||
conditions must be fulfilled to allow the connection\&.
|
||||
|
@ -1927,7 +1740,7 @@ Options for addresses with multiple connections via child processes\&.
|
|||
.IP "\fB\f(CWfork\fP\fP"
|
||||
After establishing a connection, handles its channel in a child process and
|
||||
keeps the parent process attempting to produce more connections, either by
|
||||
listening or by connecting in a loop (example)\&.
|
||||
listening or by connecting in a loop\&.
|
||||
.br
|
||||
SSL-CONNECT and SSL-LISTEN differ in when they actually fork off the child:
|
||||
SSL-LISTEN forks \fIbefore\fP the SSL handshake, while SSL-CONNECT forks
|
||||
|
@ -1991,22 +1804,22 @@ created by opening \fB/dev/ptmx\fP or \fB/dev/ptc\fP instead of the default
|
|||
Establishes communication with the sub process using a pseudo terminal
|
||||
instead of a socket pair\&. Creates the pty with an available mechanism\&. If
|
||||
openpty and ptmx are both available, it uses ptmx because this is POSIX
|
||||
compliant (example)\&.
|
||||
compliant\&.
|
||||
.IP "\fB\f(CWctty\fP\fP"
|
||||
Makes the pty the controlling tty of the sub process (example)\&.
|
||||
Makes the pty the controlling tty of the sub process\&.
|
||||
.IP "\fB\f(CWstderr\fP\fP"
|
||||
Directs stderr of the sub process to its output channel by making stderr a
|
||||
\f(CWdup()\fP of stdout (example)\&.
|
||||
\f(CWdup()\fP of stdout\&.
|
||||
.IP "\fB\f(CWfdin=<fdnum>\fP\fP"
|
||||
Assigns the sub processes input channel to its file descriptor
|
||||
<fdnum>
|
||||
instead of stdin (0)\&. The program started from the subprocess has to use
|
||||
this fd for reading data from \fBsocat\fP (example)\&.
|
||||
this fd for reading data from \fBsocat\fP\&.
|
||||
.IP "\fB\f(CWfdout=<fdnum>\fP\fP"
|
||||
Assigns the sub processes output channel to its file descriptor
|
||||
<fdnum>
|
||||
instead of stdout (1)\&. The program started from the subprocess has to use
|
||||
this fd for writing data to \fBsocat\fP (example)\&.
|
||||
this fd for writing data to \fBsocat\fP\&.
|
||||
.IP "\fB\f(CWsighup\fP\fP, \fB\f(CWsigint\fP\fP, \fB\f(CWsigquit\fP\fP"
|
||||
Has \fBsocat\fP pass an eventual signal of this type to the sub process\&.
|
||||
If no address has this option, socat terminates on these signals\&.
|
||||
|
@ -2033,12 +1846,12 @@ Note: On some operating systems, these options may not be
|
|||
available\&. Use ispeed or ospeed
|
||||
instead\&.
|
||||
.IP "\fB\f(CWecho=<bool>\fP\fP"
|
||||
Enables or disables local echo (example)\&.
|
||||
Enables or disables local echo\&.
|
||||
.IP "\fB\f(CWicanon=<bool>\fP\fP"
|
||||
Sets or clears canonical mode, enabling line buffering and some special
|
||||
characters\&.
|
||||
.IP "\fB\f(CWraw\fP\fP"
|
||||
Sets raw mode, thus passing input and output almost unprocessed (example)\&.
|
||||
Sets raw mode, thus passing input and output almost unprocessed\&.
|
||||
.IP "\fB\f(CWignbrk=<bool>\fP\fP"
|
||||
Ignores or interpretes the BREAK character (e\&.g\&., ^C)
|
||||
.IP "\fB\f(CWbrkint=<bool>\fP\fP"
|
||||
|
@ -2174,8 +1987,7 @@ Generates a symbolic link that points to the actual pseudo terminal
|
|||
to solve the problem that ptys are generated with more or less
|
||||
unpredictable names, making it difficult to directly access the socat
|
||||
generated pty automatically\&. With this option, the user can specify a "fix"
|
||||
point in the file hierarchy that helps him to access the actual pty
|
||||
(example)\&.
|
||||
point in the file hierarchy that helps him to access the actual pty\&.
|
||||
Beginning with \fBsocat\fP version 1\&.4\&.3, the symbolic link is removed when
|
||||
the address is closed (but see option unlink-close)\&.
|
||||
.IP "\fB\f(CWwait-slave\fP\fP"
|
||||
|
@ -2233,8 +2045,9 @@ this option is not provided\&.
|
|||
.IP "\f(CWTLSv1\fP"
|
||||
Select TLS protocol version 1\&.
|
||||
.IP "\fB\f(CWverify=<bool>\fP\fP"
|
||||
Controls check of the peer\'s certificate\&. Default is 1 (true)\&. Disabling
|
||||
verify might open your socket for everyone, making the encryption useless!
|
||||
Controls check of the peer\'s certificate\&. Default is 1 (true) for client and
|
||||
0 (false) for server addresses\&. Disabling verify might open your socket for
|
||||
everyone!
|
||||
.IP "\fB\f(CWcert=<filename>\fP\fP"
|
||||
Specifies the file with the certificate and private key for authentication\&.
|
||||
The certificate must be in OpenSSL format (*\&.pem)\&.
|
||||
|
@ -2295,61 +2108,6 @@ Performs an unlimited number of retry attempts\&.
|
|||
.PP
|
||||
.br
|
||||
.PP
|
||||
\fI\fBTUN option group\fP\fP
|
||||
.PP
|
||||
Options that control Linux TUN/TAP interface device addresses\&.
|
||||
.PP
|
||||
.IP "\fB\f(CWtun-device=<device-file>\fP\fP"
|
||||
Instructs socat to take another path for the TUN clone device\&. Default is
|
||||
\f(CW/dev/net/tun\fP\&.
|
||||
.IP "\fB\f(CWtun-name=<if-name>\fP\fP"
|
||||
Gives the resulting network interface a specific name instead of the system
|
||||
generated (tun0, tun1, etc\&.)
|
||||
.IP "\fB\f(CWtun-type=[tun|tap]\fP\fP"
|
||||
Sets the type of the TUN device; use this option to generate a TAP
|
||||
device\&. See the Linux docu for the difference between these types\&.
|
||||
When you try to establish a tunnel between two TUN devices, their types
|
||||
should be the same\&.
|
||||
.IP "\fB\f(CWiff-no-pi\fP\fP"
|
||||
Sets the IFF_NO_PI flag which controls if the device includes additional
|
||||
packet information in the tunnel\&.
|
||||
When you try to establish a tunnel between two TUN devices, these flags
|
||||
should have the same values\&.
|
||||
.IP "\fB\f(CWiff-up\fP\fP"
|
||||
Sets the TUN network interface status UP\&. Strongly recommended\&.
|
||||
.IP "\fB\f(CWiff-broadcast\fP\fP"
|
||||
Sets the BROADCAST flag of the TUN network interface\&.
|
||||
.IP "\fB\f(CWiff-debug\fP\fP"
|
||||
Sets the DEBUG flag of the TUN network interface\&.
|
||||
.IP "\fB\f(CWiff-loopback\fP\fP"
|
||||
Sets the LOOPBACK flag of the TUN network interface\&.
|
||||
.IP "\fB\f(CWiff-pointopoint\fP\fP"
|
||||
Sets the POINTOPOINT flag of the TUN device\&.
|
||||
.IP "\fB\f(CWiff-notrailers\fP\fP"
|
||||
Sets the NOTRAILERS flag of the TUN device\&.
|
||||
.IP "\fB\f(CWiff-running\fP\fP"
|
||||
Sets the RUNNING flag of the TUN device\&.
|
||||
.IP "\fB\f(CWiff-noarp\fP\fP"
|
||||
Sets the NOARP flag of the TUN device\&.
|
||||
.IP "\fB\f(CWiff-promisc\fP\fP"
|
||||
Sets the PROMISC flag of the TUN device\&.
|
||||
.IP "\fB\f(CWiff-allmulti\fP\fP"
|
||||
Sets the ALLMULTI flag of the TUN device\&.
|
||||
.IP "\fB\f(CWiff-master\fP\fP"
|
||||
Sets the MASTER flag of the TUN device\&.
|
||||
.IP "\fB\f(CWiff-slave\fP\fP"
|
||||
Sets the SLAVE flag of the TUN device\&.
|
||||
.IP "\fB\f(CWiff-multicast\fP\fP"
|
||||
Sets the MULTICAST flag of the TUN device\&.
|
||||
.IP "\fB\f(CWiff-portsel\fP\fP"
|
||||
Sets the PORTSEL flag of the TUN device\&.
|
||||
.IP "\fB\f(CWiff-automedia\fP\fP"
|
||||
Sets the AUTOMEDIA flag of the TUN device\&.
|
||||
.IP "\fB\f(CWiff-dynamic\fP\fP"
|
||||
Sets the DYNAMIC flag of the TUN device\&.
|
||||
.PP
|
||||
.br
|
||||
.PP
|
||||
.SH "DATA VALUES"
|
||||
.PP
|
||||
This section explains the different data types that address parameters and
|
||||
|
@ -2491,7 +2249,7 @@ second connection\&.
|
|||
\.LP
|
||||
\.nf
|
||||
\fBsocat -d -d -lmlocal2 \\
|
||||
TCP4-LISTEN:80,bind=myaddr1,reuseaddr,fork,su=nobody,range=10.0.0.0/8 \\
|
||||
TCP4-LISTEN:80,bind=myaddr1,su=nobody,fork,range=10.0.0.0/8,reuseaddr \\
|
||||
TCP4:www.domain.org:80,bind=myaddr2\fP
|
||||
\.fi
|
||||
.IP
|
||||
|
@ -2626,7 +2384,7 @@ pty is required to have ftp issue a prompt\&.
|
|||
Nevertheless, there may occur some confusion with the password and FTP
|
||||
prompts\&.
|
||||
.IP
|
||||
(\fB\f(CWsocat PTY,link=$HOME/dev/vmodem0,raw,echo=0,waitslave EXEC:\'"ssh modemserver\&.us\&.org socat - /dev/ttyS0,nonblock,raw,echo=0"\'\fP\fP)
|
||||
.IP "\fB\f(CWsocat PTY,link=$HOME/dev/vmodem0,raw,echo=0,waitslave exec:\'"ssh modemserver\&.us\&.org socat - /dev/ttyS0,nonblock,raw,echo=0"\'\fP\fP"
|
||||
.IP
|
||||
Generates a pseudo terminal
|
||||
device (PTY) on the client that can be reached under the
|
||||
|
@ -2649,31 +2407,6 @@ through the proxy daemon listening on port 3128
|
|||
CONNECT method, where they are authenticated as "user" with "pass" (proxyauth)\&. The proxy
|
||||
should establish connections to host www\&.domain\&.org on port 22 then\&.
|
||||
.IP
|
||||
.IP "\fB\f(CWsocat - SSL:server:4443,cafile=server\&.crt,cert=client\&.pem\fP\fP"
|
||||
.IP
|
||||
is an OpenSSL client that tries to establish a secure connection to an SSL
|
||||
server\&. Option cafile specifies a file that
|
||||
contains trust certificates: we trust the server only when it presents one of
|
||||
these certificates and proofs that it owns the related private key\&.
|
||||
Otherwise the connection is terminated\&.
|
||||
With cert a file containing the client certificate
|
||||
and the associated private key is specified\&. This is required in case the
|
||||
server wishes a client authentication; many Internet servers do not\&.
|
||||
.br
|
||||
The first address (\'-\') can be replaced by almost any other socat address\&.
|
||||
.IP
|
||||
.IP "\fB\f(CWsocat SSL-LISTEN:4443,reuseaddr,pf=ip4,fork,cert=server\&.pem,cafile=client\&.crt PIPE\fP\fP"
|
||||
.IP
|
||||
is an OpenSSL server that accepts TCP connections, presents the certificate
|
||||
from the file server\&.pem and forces the client to present a certificate that is
|
||||
verified against cafile\&.crt\&.
|
||||
.br
|
||||
The second address (\'PIPE\') can be replaced by almost any other socat
|
||||
address\&.
|
||||
.br
|
||||
For instructions on generating and distributing OpenSSL keys and certificates
|
||||
see the additional socat docu \f(CWsocat-openssl\&.txt\fP\&.
|
||||
.IP
|
||||
.IP "\fB\f(CWecho |socat -u - file:/tmp/bigfile,create,largefile,seek=100000000000\fP\fP"
|
||||
.IP
|
||||
creates a 100GB sparse file; this requires a file system type that
|
||||
|
@ -2697,46 +2430,7 @@ to make the squid executable from Cygwin run under Windows, actual per May 2004)
|
|||
.IP
|
||||
.IP "\fB\f(CWsocat - tcp:www\&.blackhat\&.org:31337,readbytes=1000\fP\fP"
|
||||
.IP
|
||||
connects to an unknown service and prevents being flooded\&.
|
||||
.IP
|
||||
.IP "\fB\f(CWsocat -U TCP:target:9999,end-close TCP-L:8888,reuseaddr,fork\fP\fP"
|
||||
.IP
|
||||
merges data arriving from different TCP streams on port 8888 to just one stream
|
||||
to target:9999\&. The end-close option prevents the child
|
||||
processes forked off by the second address from terminating the shared
|
||||
connection to 9999 (close(2) just unlinks the inode which stays active as long
|
||||
as the parent process lives; shutdown(2) would actively terminate the
|
||||
connection)\&.
|
||||
.IP
|
||||
.IP "\fB\f(CWsocat - UDP4-DATAGRAM:192\&.168\&.1\&.0:123,sp=123,broadcast,range=192\&.168\&.1\&.0/24\fP\fP"
|
||||
.IP
|
||||
sends a broadcast to the network 192\&.168\&.1\&.0/24 and receives the replies of the
|
||||
timeservers there\&. Ignores NTP packets from hosts outside this network\&.
|
||||
.IP
|
||||
.IP "\fB\f(CWsocat - IP4-DATAGRAM:255\&.255\&.255\&.255:44,broadcast,range=10\&.0\&.0\&.0/8\fP\fP"
|
||||
.IP
|
||||
sends a broadcast to the local network(s) using protocol 44\&. Accepts replies
|
||||
from the private address range only\&.
|
||||
.IP
|
||||
.IP "\fB\f(CWsocat - UDP4-DATAGRAM:224\&.255\&.0\&.1:6666,bind=:6666,ip-add-membership=224\&.255\&.0\&.1:eth0\fP\fP"
|
||||
.IP
|
||||
transfers data from stdin to the specified multicast address using UDP\&. Both
|
||||
local and remote ports are 6666\&. Tells the interface eth0 to also accept
|
||||
multicast packets of the given group\&. Multiple hosts on the local network can
|
||||
run this command, so all data sent by any of the hosts will be received
|
||||
by all the other ones\&. Note that there are many possible reasons for failure,
|
||||
including IP-filters, routing issues, wrong interface selection by the
|
||||
operating system, bridges, or a badly configured switch\&.
|
||||
.IP
|
||||
.IP "\fB\f(CWsocat TCP:host2:4443 TUN:192\&.168\&.255\&.1/24,up\fP\fP"
|
||||
.IP
|
||||
establishes one side of a virtual (but not private!) network with host2 where a
|
||||
similar process might run, with TCP-L and tun address 192\&.168\&.255\&.2\&. They
|
||||
can reach each other using the addresses 192\&.168\&.255\&.1 and
|
||||
192\&.168\&.255\&.2\&. Substitute the TCP link with an SSL connection protected by
|
||||
client and server authentication (see OpenSSL
|
||||
client and
|
||||
server)\&.
|
||||
connect to an unknown service and prevent being flooded\&.
|
||||
.IP
|
||||
.PP
|
||||
.SH "DIAGNOSTICS"
|
||||
|
@ -2843,12 +2537,15 @@ lots of other useful tools and libraries\&.
|
|||
The \fILinux developers community\fP (http://www\&.linux\&.org/) for providing a free, open source operating
|
||||
system\&.
|
||||
.PP
|
||||
\fISourceforge\fP (http://www\&.sourceforge\&.net/) for providing a compile
|
||||
farm with Solaris, FreeBSD, and MacOS X machines, making these ports possible\&.
|
||||
.PP
|
||||
The \fIOpen Group\fP (http://www\&.unix-systems\&.org/) for making their
|
||||
standard specifications available on the Internet for free\&.
|
||||
.PP
|
||||
.SH "VERSION"
|
||||
.PP
|
||||
This man page describes version 1\&.6\&.0 of \fBsocat\fP\&.
|
||||
This man page describes version 1\&.5\&.0 of \fBsocat\fP\&.
|
||||
.PP
|
||||
.SH "BUGS"
|
||||
.PP
|
||||
|
|
528
doc/socat.html
528
doc/socat.html
File diff suppressed because it is too large
Load diff
7
error.c
7
error.c
|
@ -176,8 +176,8 @@ void msg(int level, const char *format, ...) {
|
|||
result = gettimeofday(&now, NULL);
|
||||
if (result < 0) {
|
||||
/* invoking msg() might create endless recursion; by hand instead */
|
||||
sprintf(buff, "cannot read time: %s["F_pid"] E %s",
|
||||
diagopts.progname, getpid(), strerror(errno));
|
||||
sprintf(buff, "cannot read time: %s["F_pid".%lu] E %s",
|
||||
diagopts.progname, getpid(), (unsigned long)pthread_self(), strerror(errno));
|
||||
_msg(LOG_ERR, buff, strstr(buff, " E "+1));
|
||||
strcpy(buff, "unknown time "); bytes = 20;
|
||||
} else {
|
||||
|
@ -215,7 +215,8 @@ void msg(int level, const char *format, ...) {
|
|||
if (diagopts.withhostname) {
|
||||
bytes = sprintf(bufp, "%s ", diagopts.hostname), bufp+=bytes;
|
||||
}
|
||||
bytes = sprintf(bufp, "%s["F_pid"] ", diagopts.progname, getpid());
|
||||
bytes = sprintf(bufp, "%s["F_pid".%lu] ",
|
||||
diagopts.progname, getpid(), (unsigned long)pthread_self());
|
||||
bufp += bytes;
|
||||
syslp = bufp;
|
||||
*bufp++ = "DINWEF"[level];
|
||||
|
|
2
ftp.sh
2
ftp.sh
|
@ -80,7 +80,7 @@ TMPDIR=$(if [ -x /bin/mktemp ]; then
|
|||
(umask 077; d=/tmp/$USER/FTPSH.$$; mkdir $d; echo $d)
|
||||
fi)
|
||||
TO="$TMPDIR/to"; FROM="$TMPDIR/from"
|
||||
socat $SO1 fifo:$TO,nonblock,ignoreeof!!fifo:$FROM $method:$server:21,$addropts &
|
||||
socat $SO1 fifo:$FROM $method:$server:21,$addropts%fifo:$TO,nonblock,ignoreeof &
|
||||
S1=$!
|
||||
while ! [ -p "$TO" -a -p "$FROM" ]; do sleep 1; done
|
||||
exec 4>$TMPDIR/to 3<$TMPDIR/from
|
||||
|
|
31
nestlex.c
31
nestlex.c
|
@ -1,5 +1,5 @@
|
|||
/* $Id: nestlex.c,v 1.4 2006/06/23 17:04:36 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2006 */
|
||||
/* Copyright Gerhard Rieger 2006-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* a function for lexical scanning of nested character patterns */
|
||||
|
@ -29,6 +29,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
const char *squotes[],/* list of strings that quote softly */
|
||||
const char *nests[],/* list of strings that start nesting;
|
||||
every second one is matching end */
|
||||
bool dropspace, /* drop trailing space before end token */
|
||||
bool dropquotes, /* drop the outermost quotes */
|
||||
bool c_esc, /* solve C char escapes: \n \t \0 etc */
|
||||
bool html_esc /* solve HTML char escapes: %0d %08 etc */
|
||||
|
@ -38,6 +39,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
const char **quotx; /* loops over quote patterns */
|
||||
const char **nestx; /* loops over nest patterns */
|
||||
char *out = *token; /* pointer into output token */
|
||||
char *lastnonspace = out;
|
||||
char c;
|
||||
int i;
|
||||
int result;
|
||||
|
@ -46,7 +48,9 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
|
||||
/* is this end of input string? */
|
||||
if (*in == 0) {
|
||||
|
||||
if (dropspace) {
|
||||
out = lastnonspace;
|
||||
}
|
||||
break; /* end of string */
|
||||
}
|
||||
|
||||
|
@ -55,6 +59,9 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
while (*endx) {
|
||||
if (!strncmp(in, *endx, strlen(*endx))) {
|
||||
/* this end pattern matches */
|
||||
if (dropspace) {
|
||||
out = lastnonspace;
|
||||
}
|
||||
*addr = in;
|
||||
*token = out;
|
||||
return 0;
|
||||
|
@ -83,7 +90,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
result =
|
||||
nestlex(&in, &out, len, endnest, NULL/*hquotes*/,
|
||||
NULL/*squotes*/, NULL/*nests*/,
|
||||
false, c_esc, html_esc);
|
||||
false, false, c_esc, html_esc);
|
||||
if (result == 0 && dropquotes) {
|
||||
/* we strip this quote */
|
||||
in += strlen(*quotx);
|
||||
|
@ -101,6 +108,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
}
|
||||
if (hquotes && *quotx != NULL) {
|
||||
/* there was a quote; string might continue with hard quote */
|
||||
lastnonspace = out;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -126,7 +134,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
result =
|
||||
nestlex(&in, &out, len, endnest, hquotes,
|
||||
squotes, nests,
|
||||
false, c_esc, html_esc);
|
||||
false, false, c_esc, html_esc);
|
||||
|
||||
if (result == 0 && dropquotes) {
|
||||
/* we strip the trailing quote */
|
||||
|
@ -144,6 +152,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
}
|
||||
if (squotes && *quotx != NULL) {
|
||||
/* there was a soft quote; string might continue with any quote */
|
||||
lastnonspace = out;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -163,7 +172,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
|
||||
result =
|
||||
nestlex(&in, &out, len, endnest, hquotes, squotes, nests,
|
||||
false, c_esc, html_esc);
|
||||
false, false, c_esc, html_esc);
|
||||
if (result == 0) {
|
||||
/* copy endnest */
|
||||
i = strlen(nestx[1]); while (i > 0) {
|
||||
|
@ -182,6 +191,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
}
|
||||
if (nests && *nestx) {
|
||||
/* we handled a nested expression, continue loop */
|
||||
lastnonspace = out;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -216,6 +226,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
*token = out;
|
||||
return -1; /* output overflow */
|
||||
}
|
||||
lastnonspace = out;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -227,6 +238,9 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
*token = out;
|
||||
return -1; /* output overflow */
|
||||
}
|
||||
if (!isspace(c)) {
|
||||
lastnonspace = out;
|
||||
}
|
||||
|
||||
}
|
||||
/* never come here? */
|
||||
|
@ -235,3 +249,10 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
*token = out;
|
||||
return 0; /* OK */
|
||||
}
|
||||
|
||||
int skipsp(const char **text) {
|
||||
while (isspace(**text)) {
|
||||
++(*text);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* $Id: nestlex.h,v 1.3 2006/06/23 17:04:39 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2006 */
|
||||
/* Copyright Gerhard Rieger 2006-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __nestlex_h_included
|
||||
|
@ -15,9 +15,13 @@ int nestlex(const char **addr, /* input string; aft points to end token */
|
|||
const char *squotes[],/* list of strings that quote softly */
|
||||
const char *nests[],/* list of strings that start nesting;
|
||||
every second one is matching end */
|
||||
bool dropspace, /* drop trailing space before end token */
|
||||
bool dropquotes, /* drop the outermost quotes */
|
||||
bool c_esc, /* solve C char escapes: \n \t \0 etc */
|
||||
bool html_esc /* solve HTML char escapes: %0d %08 etc */
|
||||
);
|
||||
|
||||
extern
|
||||
int skipsp(const char **text);
|
||||
|
||||
#endif /* !defined(__nestlex_h_included) */
|
||||
|
|
2
procan.c
2
procan.c
|
@ -1,5 +1,5 @@
|
|||
/* $Id: procan.c,v 1.17 2006/12/28 07:25:01 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* the subroutine procan makes a "PROCess ANalysis". It gathers information
|
||||
|
|
276
socat.c
276
socat.c
|
@ -20,45 +20,25 @@
|
|||
#include "filan.h"
|
||||
#include "xio.h"
|
||||
#include "xioopts.h"
|
||||
#include "xiosigchld.h"
|
||||
#include "xiolockfile.h"
|
||||
|
||||
#include "xioopen.h"
|
||||
|
||||
/* command line options */
|
||||
struct {
|
||||
size_t bufsiz;
|
||||
bool verbose;
|
||||
bool verbhex;
|
||||
struct timeval pollintv; /* with ignoreeof, reread after seconds */
|
||||
struct timeval closwait; /* after close of x, die after seconds */
|
||||
struct timeval total_timeout;/* when nothing happens, die after seconds */
|
||||
bool debug;
|
||||
bool strictopts; /* stop on errors in address options */
|
||||
char logopt; /* y..syslog; s..stderr; f..file; m..mixed */
|
||||
bool lefttoright; /* first addr ro, second addr wo */
|
||||
bool righttoleft; /* first addr wo, second addr ro */
|
||||
xiolock_t lock; /* a lock file */
|
||||
} socat_opts = {
|
||||
8192, /* bufsiz */
|
||||
false, /* verbose */
|
||||
false, /* verbhex */
|
||||
{1,0}, /* pollintv */
|
||||
{0,500000}, /* closwait */
|
||||
{0,0}, /* total_timeout */
|
||||
0, /* debug */
|
||||
0, /* strictopts */
|
||||
's', /* logopt */
|
||||
false, /* lefttoright */
|
||||
false, /* righttoleft */
|
||||
{ NULL, 0 }, /* lock */
|
||||
};
|
||||
|
||||
void socat_usage(FILE *fd);
|
||||
void socat_version(FILE *fd);
|
||||
int socat(const char *address1, const char *address2);
|
||||
int _socat(void);
|
||||
int cv_newline(unsigned char **buff, ssize_t *bytes, int lineterm1, int lineterm2);
|
||||
int socat(int argc, const char *address1, const char *address2);
|
||||
int _socat(xiofile_t *xfd1, xiofile_t *xfd2);
|
||||
void socat_signal(int sig);
|
||||
static int socat_sigchild(struct single *file);
|
||||
|
||||
void lftocrlf(char **in, ssize_t *len, size_t bufsiz);
|
||||
void crlftolf(char **in, ssize_t *len, size_t bufsiz);
|
||||
|
@ -93,11 +73,11 @@ int main(int argc, const char *argv[]) {
|
|||
|
||||
/* we must init before applying options because env settings have lower
|
||||
priority and are to be overridden by options */
|
||||
if (xioinitialize() != 0) {
|
||||
if (xioinitialize(XIO_MAYALL) != 0) {
|
||||
Exit(1);
|
||||
}
|
||||
|
||||
xiosetopt('p', "!!");
|
||||
xiosetopt('p', "%");
|
||||
xiosetopt('o', ":");
|
||||
|
||||
argc0 = argc; /* save for later use */
|
||||
|
@ -114,14 +94,14 @@ int main(int argc, const char *argv[]) {
|
|||
#endif /* WITH_HELP */
|
||||
case 'd': diag_set('d', NULL); break;
|
||||
#if WITH_FILAN
|
||||
case 'D': socat_opts.debug = true; break;
|
||||
case 'D': xioparams->debug = true; break;
|
||||
#endif
|
||||
case 'l':
|
||||
switch (arg1[0][2]) {
|
||||
case 'm': /* mixed mode: stderr, then switch to syslog; + facility */
|
||||
diag_set('s', NULL);
|
||||
xiosetopt('l', "m");
|
||||
socat_opts.logopt = arg1[0][2];
|
||||
xioparams->logopt = arg1[0][2];
|
||||
xiosetopt('y', &arg1[0][3]);
|
||||
break;
|
||||
case 'y': /* syslog + facility */
|
||||
|
@ -152,8 +132,8 @@ int main(int argc, const char *argv[]) {
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case 'v': socat_opts.verbose = true; break;
|
||||
case 'x': socat_opts.verbhex = true; break;
|
||||
case 'v': xioparams->verbose = true; break;
|
||||
case 'x': xioparams->verbhex = true; break;
|
||||
case 'b': if (arg1[0][2]) {
|
||||
a = *arg1+2;
|
||||
} else {
|
||||
|
@ -163,7 +143,7 @@ int main(int argc, const char *argv[]) {
|
|||
Exit(1);
|
||||
}
|
||||
}
|
||||
socat_opts.bufsiz = strtoul(a, (char **)&a, 0);
|
||||
xioparams->bufsiz = strtoul(a, (char **)&a, 0);
|
||||
break;
|
||||
case 's':
|
||||
diag_set_int('e', E_FATAL); break;
|
||||
|
@ -177,9 +157,9 @@ int main(int argc, const char *argv[]) {
|
|||
}
|
||||
}
|
||||
rto = strtod(a, (char **)&a);
|
||||
socat_opts.closwait.tv_sec = rto;
|
||||
socat_opts.closwait.tv_usec =
|
||||
(rto-socat_opts.closwait.tv_sec) * 1000000;
|
||||
xioparams->closwait.tv_sec = rto;
|
||||
xioparams->closwait.tv_usec =
|
||||
(rto-xioparams->closwait.tv_sec) * 1000000;
|
||||
break;
|
||||
case 'T': if (arg1[0][2]) {
|
||||
a = *arg1+2;
|
||||
|
@ -191,12 +171,12 @@ int main(int argc, const char *argv[]) {
|
|||
}
|
||||
}
|
||||
rto = strtod(a, (char **)&a);
|
||||
socat_opts.total_timeout.tv_sec = rto;
|
||||
socat_opts.total_timeout.tv_usec =
|
||||
(rto-socat_opts.total_timeout.tv_sec) * 1000000;
|
||||
xioparams->total_timeout.tv_sec = rto;
|
||||
xioparams->total_timeout.tv_usec =
|
||||
(rto-xioparams->total_timeout.tv_sec) * 1000000;
|
||||
break;
|
||||
case 'u': socat_opts.lefttoright = true; break;
|
||||
case 'U': socat_opts.righttoleft = true; break;
|
||||
case 'u': xioparams->lefttoright = true; break;
|
||||
case 'U': xioparams->righttoleft = true; break;
|
||||
case 'g': xioopts_ignoregroups = true; break;
|
||||
case 'L': if (socat_opts.lock.lockfile)
|
||||
Error("only one -L and -W option allowed");
|
||||
|
@ -237,8 +217,9 @@ int main(int argc, const char *argv[]) {
|
|||
break;
|
||||
#endif /* WITH_IP4 || WITH_IP6 */
|
||||
case '\0':
|
||||
case '-': /*! this is hardcoded "--" */
|
||||
case ',':
|
||||
case ':': break; /* this "-" is a variation of STDIO */
|
||||
case ':': break; /* this "-" is a variation of STDIO or -- */
|
||||
default:
|
||||
xioinqopt('p', buff, sizeof(buff));
|
||||
if (arg1[0][1] == buff[0]) {
|
||||
|
@ -251,15 +232,20 @@ int main(int argc, const char *argv[]) {
|
|||
xioinqopt('p', buff, sizeof(buff));
|
||||
if (arg1[0][0] == '-' &&
|
||||
(arg1[0][1] == '\0' || arg1[0][1] == ':' ||
|
||||
arg1[0][1] == ',' || arg1[0][1] == buff[0]))
|
||||
arg1[0][1] == ',' || arg1[0][1] == '-'/*!*/ ||
|
||||
arg1[0][1] == buff[0]))
|
||||
break;
|
||||
++arg1; --argc;
|
||||
}
|
||||
#if 0
|
||||
Info1("%d address arguments", argc);
|
||||
#else
|
||||
if (argc != 2) {
|
||||
Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc);
|
||||
Exit(1);
|
||||
}
|
||||
if (socat_opts.lefttoright && socat_opts.righttoleft) {
|
||||
#endif
|
||||
if (xioparams->lefttoright && xioparams->righttoleft) {
|
||||
Error("-U and -u must not be combined");
|
||||
}
|
||||
|
||||
|
@ -291,6 +277,26 @@ int main(int argc, const char *argv[]) {
|
|||
Signal(SIGFPE, socat_signal);
|
||||
Signal(SIGSEGV, socat_signal);
|
||||
Signal(SIGTERM, socat_signal);
|
||||
#if HAVE_SIGACTION
|
||||
{
|
||||
struct sigaction act;
|
||||
memset(&act, 0, sizeof(struct sigaction));
|
||||
act.sa_flags = SA_NOCLDSTOP|SA_RESTART|SA_SIGINFO
|
||||
#ifdef SA_NOMASK
|
||||
|SA_NOMASK
|
||||
#endif
|
||||
;
|
||||
act.sa_sigaction = xiosigaction_subaddr_ok;
|
||||
if (Sigaction(SIGUSR1, &act, NULL) < 0) {
|
||||
/*! Linux man does not explicitely say that errno is defined */
|
||||
Warn1("sigaction(SIGUSR1, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
#else /* !HAVE_SIGACTION */
|
||||
if (Signal(SIGUSR1, xiosigaction_subaddr_ok) == SIG_ERR) {
|
||||
Warn1("signal(SIGCHLD, xiosigaction_subaddr_ok): %s", strerror(errno));
|
||||
}
|
||||
#endif /* !HAVE_SIGACTION */
|
||||
|
||||
/* set xio hooks */
|
||||
xiohook_newchild = &socat_newchild;
|
||||
|
@ -304,7 +310,7 @@ int main(int argc, const char *argv[]) {
|
|||
|
||||
Atexit(socat_unlock);
|
||||
|
||||
result = socat(arg1[0], arg1[1]);
|
||||
result = socat(argc, arg1[0], arg1[1]);
|
||||
Notice1("exiting with status %d", result);
|
||||
Exit(result);
|
||||
return 0; /* not reached, just for gcc -Wall */
|
||||
|
@ -516,125 +522,75 @@ void socat_version(FILE *fd) {
|
|||
}
|
||||
|
||||
|
||||
xiofile_t *sock1, *sock2;
|
||||
int closing = 0; /* 0..no eof yet, 1..first eof just occurred,
|
||||
2..counting down closing timeout */
|
||||
|
||||
/* call this function when the common command line options are parsed, and the
|
||||
addresses are extracted (but not resolved). */
|
||||
int socat(const char *address1, const char *address2) {
|
||||
int mayexec;
|
||||
int socat(int argc, const char *address1, const char *address2) {
|
||||
xiofile_t *xfd1, *xfd2;
|
||||
|
||||
xioinitialize(XIO_MAYALL);
|
||||
#if 1
|
||||
if (Signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
||||
Warn1("signal(SIGPIPE, SIG_IGN): %s", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (socat_opts.lefttoright) {
|
||||
if ((sock1 = xioopen(address1, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
|
||||
/* open the first (left most) address */
|
||||
if (xioparams->lefttoright) {
|
||||
if ((xfd1 = socat_open(address1, XIO_RDONLY, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
xiosetsigchild(sock1, socat_sigchild);
|
||||
} else if (socat_opts.righttoleft) {
|
||||
if ((sock1 = xioopen(address1, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
|
||||
} else if (xioparams->righttoleft) {
|
||||
if ((xfd1 = socat_open(address1, XIO_WRONLY, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
xiosetsigchild(sock1, socat_sigchild);
|
||||
} else {
|
||||
if ((sock1 = xioopen(address1, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
|
||||
if ((xfd1 = socat_open(address1, XIO_RDWR, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
xiosetsigchild(sock1, socat_sigchild);
|
||||
}
|
||||
xiosetsigchild(xfd1, socat_sigchild);
|
||||
#if 1 /*! */
|
||||
if (XIO_READABLE(sock1) &&
|
||||
(XIO_RDSTREAM(sock1)->howtoend == END_KILL ||
|
||||
XIO_RDSTREAM(sock1)->howtoend == END_CLOSE_KILL ||
|
||||
XIO_RDSTREAM(sock1)->howtoend == END_SHUTDOWN_KILL)) {
|
||||
if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown1) {
|
||||
/* child has alread died... but it might have put regular data into
|
||||
the communication channel, so continue */
|
||||
Info1("child "F_pid" has already died (diedunknown1)",
|
||||
XIO_RDSTREAM(sock1)->para.exec.pid);
|
||||
diedunknown1 = 0;
|
||||
XIO_RDSTREAM(sock1)->para.exec.pid = 0;
|
||||
if (XIO_RDSTREAM(xfd1)->subaddrstat < 0) {
|
||||
Info1("child "F_pid" has already died",
|
||||
XIO_RDSTREAM(xfd1)->child.pid);
|
||||
XIO_RDSTREAM(xfd1)->child.pid = 0;
|
||||
/* return STAT_RETRYLATER; */
|
||||
} else if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown2) {
|
||||
Info1("child "F_pid" has already died (diedunknown2)",
|
||||
XIO_RDSTREAM(sock1)->para.exec.pid);
|
||||
diedunknown2 = 0;
|
||||
XIO_RDSTREAM(sock1)->para.exec.pid = 0;
|
||||
} else if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown3) {
|
||||
Info1("child "F_pid" has already died (diedunknown3)",
|
||||
XIO_RDSTREAM(sock1)->para.exec.pid);
|
||||
diedunknown3 = 0;
|
||||
XIO_RDSTREAM(sock1)->para.exec.pid = 0;
|
||||
} else if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown4) {
|
||||
Info1("child "F_pid" has already died (diedunknown4)",
|
||||
XIO_RDSTREAM(sock1)->para.exec.pid);
|
||||
diedunknown4 = 0;
|
||||
XIO_RDSTREAM(sock1)->para.exec.pid = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
mayexec = (sock1->common.flags&XIO_DOESCONVERT ? 0 : XIO_MAYEXEC);
|
||||
if (XIO_WRITABLE(sock1)) {
|
||||
if (XIO_READABLE(sock1)) {
|
||||
if ((sock2 = xioopen(address2, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
|
||||
/* second (right) addresses chain */
|
||||
if (XIO_WRITABLE(xfd1)) {
|
||||
if (XIO_READABLE(xfd1)) {
|
||||
if ((xfd2 = socat_open(address2, XIO_RDWR, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYEXEC|XIO_MAYCONVERT)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
xiosetsigchild(sock2, socat_sigchild);
|
||||
} else {
|
||||
if ((sock2 = xioopen(address2, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
|
||||
if ((xfd2 = socat_open(address2, XIO_RDONLY, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYEXEC|XIO_MAYCONVERT)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
xiosetsigchild(sock2, socat_sigchild);
|
||||
}
|
||||
} else { /* assuming sock1 is readable */
|
||||
if ((sock2 = xioopen(address2, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
|
||||
if ((xfd2 = socat_open(address2, XIO_WRONLY, XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYEXEC|XIO_MAYCONVERT)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
xiosetsigchild(sock2, socat_sigchild);
|
||||
}
|
||||
xiosetsigchild(xfd2, socat_sigchild);
|
||||
#if 1 /*! */
|
||||
if (XIO_READABLE(sock2) &&
|
||||
(XIO_RDSTREAM(sock2)->howtoend == END_KILL ||
|
||||
XIO_RDSTREAM(sock2)->howtoend == END_CLOSE_KILL ||
|
||||
XIO_RDSTREAM(sock2)->howtoend == END_SHUTDOWN_KILL)) {
|
||||
if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown1) {
|
||||
/* child has alread died... but it might have put regular data into
|
||||
the communication channel, so continue */
|
||||
Info1("child "F_pid" has already died (diedunknown1)",
|
||||
XIO_RDSTREAM(sock2)->para.exec.pid);
|
||||
diedunknown1 = 0;
|
||||
XIO_RDSTREAM(sock2)->para.exec.pid = 0;
|
||||
if (XIO_RDSTREAM(xfd2)->subaddrstat < 0) {
|
||||
Info1("child "F_pid" has already died",
|
||||
XIO_RDSTREAM(xfd2)->child.pid);
|
||||
XIO_RDSTREAM(xfd2)->child.pid = 0;
|
||||
/* return STAT_RETRYLATER; */
|
||||
} else if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown2) {
|
||||
Info1("child "F_pid" has already died (diedunknown2)",
|
||||
XIO_RDSTREAM(sock2)->para.exec.pid);
|
||||
diedunknown2 = 0;
|
||||
XIO_RDSTREAM(sock2)->para.exec.pid = 0;
|
||||
} else if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown3) {
|
||||
Info1("child "F_pid" has already died (diedunknown3)",
|
||||
XIO_RDSTREAM(sock2)->para.exec.pid);
|
||||
diedunknown3 = 0;
|
||||
XIO_RDSTREAM(sock2)->para.exec.pid = 0;
|
||||
} else if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown4) {
|
||||
Info1("child "F_pid" has already died (diedunknown4)",
|
||||
XIO_RDSTREAM(sock2)->para.exec.pid);
|
||||
diedunknown4 = 0;
|
||||
XIO_RDSTREAM(sock2)->para.exec.pid = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Info("resolved and opened all sock addresses");
|
||||
return
|
||||
_socat(); /* nsocks, sockets are visible outside function */
|
||||
_socat(xfd1, xfd2);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/* checks if this is a connection to a child process, and if so, sees if the
|
||||
child already died, leaving some data for us.
|
||||
returns <0 if an error occurred;
|
||||
|
@ -646,10 +602,10 @@ int childleftdata(xiofile_t *xfd) {
|
|||
int retval;
|
||||
/* have to check if a child process died before, but left read data */
|
||||
if (XIO_READABLE(xfd) &&
|
||||
(XIO_RDSTREAM(xfd)->howtoend == END_KILL ||
|
||||
XIO_RDSTREAM(xfd)->howtoend == END_CLOSE_KILL ||
|
||||
XIO_RDSTREAM(xfd)->howtoend == END_SHUTDOWN_KILL) &&
|
||||
XIO_RDSTREAM(xfd)->para.exec.pid == 0) {
|
||||
(/*0 XIO_RDSTREAM(xfd)->howtoclose == END_KILL ||*/
|
||||
XIO_RDSTREAM(xfd)->howtoclose == END_CLOSE_KILL ||
|
||||
XIO_RDSTREAM(xfd)->howtoclose == END_SHUTDOWN_KILL) &&
|
||||
XIO_RDSTREAM(xfd)->child.pid == 0) {
|
||||
struct timeval time0 = { 0,0 };
|
||||
|
||||
FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt);
|
||||
|
@ -658,17 +614,17 @@ int childleftdata(xiofile_t *xfd) {
|
|||
/*0 FD_SET(XIO_GETRDFD(xfd), &expt);*/
|
||||
}
|
||||
do {
|
||||
retval = Select(FOPEN_MAX, &in, &out, &expt, &time0);
|
||||
retval = Select(FD_SETSIZE, &in, &out, &expt, &time0);
|
||||
} while (retval < 0 && errno == EINTR);
|
||||
|
||||
if (retval < 0) {
|
||||
#if HAVE_FDS_BITS
|
||||
Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s",
|
||||
FOPEN_MAX, in.fds_bits[0], out.fds_bits[0],
|
||||
FD_SETSIZE, in.fds_bits[0], out.fds_bits[0],
|
||||
expt.fds_bits[0], strerror(errno));
|
||||
#else
|
||||
Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s",
|
||||
FOPEN_MAX, in.__fds_bits[0], out.__fds_bits[0],
|
||||
FD_SETSIZE, in.__fds_bits[0], out.__fds_bits[0],
|
||||
expt.__fds_bits[0], strerror(errno));
|
||||
#endif
|
||||
return -1;
|
||||
|
@ -681,9 +637,9 @@ int childleftdata(xiofile_t *xfd) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
||||
unsigned char **buff, size_t bufsiz, bool righttoleft);
|
||||
#if 0
|
||||
|
||||
bool mayrd1; /* sock1 has read data or eof, according to select() */
|
||||
bool mayrd2; /* sock2 has read data or eof, according to select() */
|
||||
|
@ -693,7 +649,7 @@ bool maywr2; /* sock2 can be written to, according to select() */
|
|||
/* here we come when the sockets are opened (in the meaning of C language),
|
||||
and their options are set/applied
|
||||
returns -1 on error or 0 on success */
|
||||
int _socat(void) {
|
||||
int _socat(xiofile_t *xfd1, xiofile_t *xfd2) {
|
||||
fd_set in, out, expt;
|
||||
int retval;
|
||||
unsigned char *buff;
|
||||
|
@ -702,6 +658,9 @@ int _socat(void) {
|
|||
int wasaction = 1; /* last select was active, do NOT sleep before next */
|
||||
struct timeval total_timeout; /* the actual total timeout timer */
|
||||
|
||||
sock1 = xfd1;
|
||||
sock2 = xfd2;
|
||||
|
||||
#if WITH_FILAN
|
||||
if (socat_opts.debug) {
|
||||
int fdi, fdo;
|
||||
|
@ -732,7 +691,7 @@ int _socat(void) {
|
|||
#endif /* WITH_FILAN */
|
||||
|
||||
/* when converting nl to crnl, size might double */
|
||||
buff = Malloc(2*socat_opts.bufsiz+1);
|
||||
buff = Malloc(2*xioparams->bufsiz+1);
|
||||
if (buff == NULL) return -1;
|
||||
|
||||
if (socat_opts.logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') {
|
||||
|
@ -818,6 +777,7 @@ int _socat(void) {
|
|||
if (XIO_READABLE(sock1) &&
|
||||
!(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof) &&
|
||||
!socat_opts.righttoleft) {
|
||||
Debug3("*** sock1: %p [%d,%d]", sock1, XIO_GETRDFD(sock1), XIO_GETWRFD(sock1));
|
||||
if (!mayrd1) {
|
||||
FD_SET(XIO_GETRDFD(sock1), &in);
|
||||
}
|
||||
|
@ -828,6 +788,7 @@ int _socat(void) {
|
|||
if (XIO_READABLE(sock2) &&
|
||||
!(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof) &&
|
||||
!socat_opts.lefttoright) {
|
||||
Debug3("*** sock2: %p [%d,%d]", sock2, XIO_GETRDFD(sock2), XIO_GETWRFD(sock2));
|
||||
if (!mayrd2) {
|
||||
FD_SET(XIO_GETRDFD(sock2), &in);
|
||||
}
|
||||
|
@ -835,7 +796,7 @@ int _socat(void) {
|
|||
FD_SET(XIO_GETWRFD(sock1), &out);
|
||||
}
|
||||
}
|
||||
retval = Select(FOPEN_MAX, &in, &out, &expt, to);
|
||||
retval = Select(FD_SETSIZE, &in, &out, &expt, to);
|
||||
_errno = errno;
|
||||
if (retval < 0 && errno == EINTR) {
|
||||
Info1("select(): %s", strerror(errno));
|
||||
|
@ -851,12 +812,12 @@ int _socat(void) {
|
|||
if (retval < 0) {
|
||||
#if HAVE_FDS_BITS
|
||||
Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s",
|
||||
FOPEN_MAX, in.fds_bits[0], out.fds_bits[0],
|
||||
FD_SETSIZE, in.fds_bits[0], out.fds_bits[0],
|
||||
expt.fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0,
|
||||
strerror(errno));
|
||||
#else
|
||||
Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s",
|
||||
FOPEN_MAX, in.__fds_bits[0], out.__fds_bits[0],
|
||||
FD_SETSIZE, in.__fds_bits[0], out.__fds_bits[0],
|
||||
expt.__fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0,
|
||||
strerror(errno));
|
||||
#endif
|
||||
|
@ -900,7 +861,7 @@ int _socat(void) {
|
|||
|
||||
if (mayrd1 && maywr2) {
|
||||
mayrd1 = false;
|
||||
if ((bytes1 = xiotransfer(sock1, sock2, &buff, socat_opts.bufsiz, false))
|
||||
if ((bytes1 = xiotransfer(sock1, sock2, &buff, xioparams->bufsiz, false))
|
||||
< 0) {
|
||||
if (errno != EAGAIN) {
|
||||
closing = MAX(closing, 1);
|
||||
|
@ -920,15 +881,22 @@ int _socat(void) {
|
|||
/* avoid idle when all readbytes already there */
|
||||
mayrd1 = true;
|
||||
}
|
||||
} else { /* bytes2 == 0 */
|
||||
if (XIO_RDSTREAM(sock1)->ignoreeof && !closing) {
|
||||
;
|
||||
} else {
|
||||
XIO_RDSTREAM(sock1)->eof = 2;
|
||||
closing = MAX(closing, 1);
|
||||
}
|
||||
/* (bytes1 == 0) handled later */
|
||||
}
|
||||
} else {
|
||||
bytes1 = -1;
|
||||
}
|
||||
|
||||
if (mayrd2 && maywr1) {
|
||||
mayrd2 = false;
|
||||
if ((bytes2 = xiotransfer(sock2, sock1, &buff, socat_opts.bufsiz, true))
|
||||
if ((bytes2 = xiotransfer(sock2, sock1, &buff, xioparams->bufsiz, true))
|
||||
< 0) {
|
||||
if (errno != EAGAIN) {
|
||||
closing = MAX(closing, 1);
|
||||
|
@ -948,8 +916,15 @@ int _socat(void) {
|
|||
/* avoid idle when all readbytes already there */
|
||||
mayrd2 = true;
|
||||
}
|
||||
} else { /* bytes == 0 */
|
||||
if (XIO_RDSTREAM(sock2)->ignoreeof && !closing) {
|
||||
;
|
||||
} else {
|
||||
XIO_RDSTREAM(sock2)->eof = 2;
|
||||
closing = MAX(closing, 1);
|
||||
}
|
||||
/* (bytes2 == 0) handled later */
|
||||
}
|
||||
} else {
|
||||
bytes2 = -1;
|
||||
}
|
||||
|
@ -959,7 +934,7 @@ int _socat(void) {
|
|||
if (bytes1 == 0 || XIO_RDSTREAM(sock1)->eof >= 2) {
|
||||
if (XIO_RDSTREAM(sock1)->ignoreeof && !closing) {
|
||||
Debug1("socket 1 (fd %d) is at EOF, ignoring",
|
||||
XIO_RDSTREAM(sock1)->fd); /*! */
|
||||
XIO_RDSTREAM(sock1)->fd1); /*! */
|
||||
polling = 1;
|
||||
} else {
|
||||
Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1));
|
||||
|
@ -973,7 +948,7 @@ int _socat(void) {
|
|||
if (bytes2 == 0 || XIO_RDSTREAM(sock2)->eof >= 2) {
|
||||
if (XIO_RDSTREAM(sock2)->ignoreeof && !closing) {
|
||||
Debug1("socket 2 (fd %d) is at EOF, ignoring",
|
||||
XIO_RDSTREAM(sock2)->fd);
|
||||
XIO_RDSTREAM(sock2)->fd1);
|
||||
polling = 1;
|
||||
} else {
|
||||
Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2));
|
||||
|
@ -991,8 +966,9 @@ int _socat(void) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
|
||||
#if 0
|
||||
#define MAXTIMESTAMPLEN 128
|
||||
/* prints the timestamp to the buffer and terminates it with '\0'. This buffer
|
||||
should be at least MAXTIMESTAMPLEN bytes long.
|
||||
|
@ -1035,7 +1011,9 @@ int gettimestamp(char *timestamp) {
|
|||
#endif /* !HAVE_GETTIMEOFDAY */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static const char *prefixltor = "> ";
|
||||
static const char *prefixrtol = "< ";
|
||||
static unsigned long numltor;
|
||||
|
@ -1061,8 +1039,9 @@ static int
|
|||
fputs(buff, file);
|
||||
return 0;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
|
||||
#if 0
|
||||
/* inpipe is suspected to have read data available; read at most bufsiz bytes
|
||||
and transfer them to outpipe. Perform required data conversions.
|
||||
buff should be at least twice as large as bufsiz, to allow all standard
|
||||
|
@ -1078,7 +1057,7 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
|||
unsigned char **buff, size_t bufsiz, bool righttoleft) {
|
||||
ssize_t bytes, writt;
|
||||
|
||||
bytes = xioread(inpipe, *buff, socat_opts.bufsiz);
|
||||
bytes = xioread(inpipe, *buff, xioparams->bufsiz);
|
||||
if (bytes < 0) {
|
||||
if (errno != EAGAIN)
|
||||
XIO_RDSTREAM(inpipe)->eof = 2;
|
||||
|
@ -1105,7 +1084,7 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
|||
errno = EAGAIN; return -1;
|
||||
}
|
||||
|
||||
if (socat_opts.verbose && socat_opts.verbhex) {
|
||||
if (xioparams->verbose && xioparams->verbhex) {
|
||||
/* Hack-o-rama */
|
||||
size_t i = 0;
|
||||
size_t j;
|
||||
|
@ -1178,7 +1157,7 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
|||
}
|
||||
++i;
|
||||
}
|
||||
} else if (socat_opts.verbhex) {
|
||||
} else if (xioparams->verbhex) {
|
||||
int i;
|
||||
/*! prefix? */
|
||||
for (i = 0; i < bytes; ++i) {
|
||||
|
@ -1206,11 +1185,13 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
|||
}
|
||||
return writt;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
#if 0
|
||||
|
||||
#define CR '\r'
|
||||
#define LF '\n'
|
||||
|
||||
|
||||
int cv_newline(unsigned char **buff, ssize_t *bytes,
|
||||
int lineterm1, int lineterm2) {
|
||||
/* must perform newline changes */
|
||||
|
@ -1260,7 +1241,7 @@ int cv_newline(unsigned char **buff, ssize_t *bytes,
|
|||
} else {
|
||||
from = '\r';
|
||||
}
|
||||
if ((buf2 = Malloc(2*socat_opts.bufsiz+1)) == NULL) {
|
||||
if ((buf2 = Malloc(2*xioparams->bufsiz+1)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
s = *buff; t = buf2; z = *buff + *bytes;
|
||||
|
@ -1279,6 +1260,7 @@ int cv_newline(unsigned char **buff, ssize_t *bytes,
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
void socat_signal(int signum) {
|
||||
switch (signum) {
|
||||
|
@ -1302,6 +1284,7 @@ void socat_signal(int signum) {
|
|||
Exit(128+signum);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* this is the callback when the child of an address died */
|
||||
static int socat_sigchild(struct single *file) {
|
||||
if (file->ignoreeof && !closing) {
|
||||
|
@ -1312,6 +1295,7 @@ static int socat_sigchild(struct single *file) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int socat_lock(void) {
|
||||
int lockrc;
|
||||
|
|
16
sslcls.c
16
sslcls.c
|
@ -197,6 +197,22 @@ int sycSSL_set_fd(SSL *ssl, int fd) {
|
|||
return result;
|
||||
}
|
||||
|
||||
int sycSSL_set_rfd(SSL *ssl, int fd) {
|
||||
int result;
|
||||
Debug2("SSL_set_rfd(%p, %d)", ssl, fd);
|
||||
result = SSL_set_rfd(ssl, fd);
|
||||
Debug1("SSL_set_rfd() -> %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int sycSSL_set_wfd(SSL *ssl, int fd) {
|
||||
int result;
|
||||
Debug2("SSL_set_wfd(%p, %d)", ssl, fd);
|
||||
result = SSL_set_wfd(ssl, fd);
|
||||
Debug1("SSL_set_wfd() -> %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int sycSSL_connect(SSL *ssl) {
|
||||
int result;
|
||||
Debug1("SSL_connect(%p)", ssl);
|
||||
|
|
4
sslcls.h
4
sslcls.h
|
@ -32,6 +32,8 @@ int sycSSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str);
|
|||
int sycSSL_set_cipher_list(SSL *ssl, const char *str);
|
||||
long sycSSL_get_verify_result(SSL *ssl);
|
||||
int sycSSL_set_fd(SSL *ssl, int fd);
|
||||
int sycSSL_set_rfd(SSL *ssl, int fd);
|
||||
int sycSSL_set_wfd(SSL *ssl, int fd);
|
||||
int sycSSL_connect(SSL *ssl);
|
||||
int sycSSL_accept(SSL *ssl);
|
||||
int sycSSL_read(SSL *ssl, void *buf, int num);
|
||||
|
@ -77,6 +79,8 @@ int sycFIPS_mode_set(int onoff);
|
|||
#define sycSSL_set_cipher_list(s,t) SSL_set_cipher_list(s,t)
|
||||
#define sycSSL_get_verify_result(s) SSL_get_verify_result(s)
|
||||
#define sycSSL_set_fd(s,f) SSL_set_fd(s,f)
|
||||
#define sycSSL_set_rfd(s,f) SSL_set_rfd(s,f)
|
||||
#define sycSSL_set_wfd(s,f) SSL_set_wfd(s,f)
|
||||
#define sycSSL_connect(s) SSL_connect(s)
|
||||
#define sycSSL_accept(s) SSL_accept(s)
|
||||
#define sycSSL_read(s,b,n) SSL_read(s,b,n)
|
||||
|
|
111
sycls.c
111
sycls.c
|
@ -720,6 +720,41 @@ int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
|||
return result;
|
||||
}
|
||||
|
||||
/* we only show the first word of the fd_set's; hope this is enough for most
|
||||
cases. */
|
||||
int Pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
struct timespec *timeout, const sigset_t *sigmask) {
|
||||
int result, _errno;
|
||||
#if HAVE_FDS_BITS
|
||||
Debug8("pselect(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu.%06u, {0x%lx})",
|
||||
n, readfds->fds_bits[0], writefds->fds_bits[0],
|
||||
exceptfds->fds_bits[0],
|
||||
timeout?"&":"NULL/", timeout?timeout->tv_sec:0,
|
||||
timeout?timeout->tv_nsec:0, /*sigmask->__val[0]*/
|
||||
*(unsigned long *)sigmask);
|
||||
#else
|
||||
Debug8("pselect(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu.%06u, {0x%lx})",
|
||||
n, readfds->__fds_bits[0], writefds->__fds_bits[0],
|
||||
exceptfds->__fds_bits[0],
|
||||
timeout?"&":"NULL/", timeout?timeout->tv_sec:0,
|
||||
timeout?timeout->tv_nsec:0, *(unsigned long *)sigmask);
|
||||
#endif
|
||||
result = pselect(n, readfds, writefds, exceptfds, timeout, sigmask);
|
||||
_errno = errno;
|
||||
#if HAVE_FDS_BITS
|
||||
Debug4("pselect -> (, 0x%lx, 0x%lx, 0x%lx, , ), %d",
|
||||
readfds->fds_bits[0], writefds->fds_bits[0], exceptfds->fds_bits[0],
|
||||
result);
|
||||
#else
|
||||
Debug4("pselect -> (, 0x%lx, 0x%lx, 0x%lx, , ), %d",
|
||||
readfds->__fds_bits[0], writefds->__fds_bits[0],
|
||||
exceptfds->__fds_bits[0],
|
||||
result);
|
||||
#endif
|
||||
errno = _errno;
|
||||
return result;
|
||||
}
|
||||
|
||||
pid_t Fork(void) {
|
||||
pid_t pid;
|
||||
int _errno;
|
||||
|
@ -764,12 +799,15 @@ int Sigaction(int signum, const struct sigaction *act,
|
|||
}
|
||||
#endif /* HAVE_SIGACTION */
|
||||
|
||||
int Sigprocmask(int how, const sigset_t *set, sigset_t *oset) {
|
||||
int retval;
|
||||
Debug3("sigprocmask(%d, %p, %p)", how, set, oset);
|
||||
retval = sigprocmask(how, set, oset);
|
||||
Debug1("sigprocmask() -> %d", retval);
|
||||
return retval;
|
||||
int Sigprocmask(int how, const sigset_t *set, sigset_t *oldset) {
|
||||
int _errno, result;
|
||||
Debug3("sigprocmask(%d, {0x%lx}, %p)", how, *(unsigned long *)set, oldset);
|
||||
result = sigprocmask(how, set, oldset);
|
||||
_errno = errno;
|
||||
Debug4("sigprocmask(,,%s%lu%s) -> %d",
|
||||
oldset?" {0x":"", oldset?*(unsigned long *)oldset:0, oldset?"}":"", result);
|
||||
errno = _errno;
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int Alarm(unsigned int seconds) {
|
||||
|
@ -1138,7 +1176,7 @@ int Pause(void) {
|
|||
return retval;
|
||||
}
|
||||
|
||||
#if WITH_IP4 || WITH_IP6
|
||||
#if _WITH_IP4 || _WITH_IP6
|
||||
struct hostent *Gethostbyname(const char *name) {
|
||||
struct hostent *hent;
|
||||
Debug1("gethostbyname(\"%s\")", name);
|
||||
|
@ -1154,7 +1192,7 @@ struct hostent *Gethostbyname(const char *name) {
|
|||
}
|
||||
return hent;
|
||||
}
|
||||
#endif /* WITH_IP4 || WITH_IP6 */
|
||||
#endif /* _WITH_IP4 || _WITH_IP6 */
|
||||
|
||||
#if (_WITH_IP4 || _WITH_IP6) && HAVE_GETADDRINFO
|
||||
int Getaddrinfo(const char *node, const char *service,
|
||||
|
@ -1397,6 +1435,27 @@ void Abort(void) {
|
|||
abort();
|
||||
}
|
||||
|
||||
int Pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||
void *(*start_routine)(void *), void *arg) {
|
||||
int result, _errno;
|
||||
Debug4("pthread_create(%p, %p, %p, %p)", thread, attr, start_routine, arg);
|
||||
result = pthread_create(thread, attr, start_routine, arg);
|
||||
_errno = errno;
|
||||
Debug1("pthread_create() -> %d", errno);
|
||||
errno = _errno;
|
||||
return result;
|
||||
}
|
||||
|
||||
int Pthread_join(pthread_t thread, void **value_ptr) {
|
||||
int result, _errno;
|
||||
Debug2("pthread_join(%p, %p)", thread, value_ptr);
|
||||
result = pthread_join(thread, value_ptr);
|
||||
_errno = errno;
|
||||
Debug1("pthread_join() -> %d", errno);
|
||||
errno = _errno;
|
||||
return result;
|
||||
}
|
||||
|
||||
int Mkstemp(char *template) {
|
||||
int result, _errno;
|
||||
Debug1("mkstemp(\"%s\")", template);
|
||||
|
@ -1500,4 +1559,40 @@ void Add_history(const char *string) {
|
|||
|
||||
#endif /* WITH_READLINE */
|
||||
|
||||
#if WITH_GZIP
|
||||
|
||||
gzFile Gzdopen(int fd, const char *mode) {
|
||||
gzFile result;
|
||||
Debug2("gzdopen(%d, \"%s\")", fd, mode);
|
||||
result = gzdopen(fd, mode);
|
||||
Debug1("gzdopen() -> %p", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int Gzread(gzFile file, voidp buf, unsigned len) {
|
||||
int result;
|
||||
Debug3("gzread(%p, %p, %u)", file, buf, len);
|
||||
result = gzread(file, buf, len);
|
||||
Debug1("gzread() -> %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int Gzwrite(gzFile file, const voidp buf, unsigned len) {
|
||||
int result;
|
||||
Debug3("gzwrite(%p, %p, %u)", file, buf, len);
|
||||
result = gzwrite(file, buf, len);
|
||||
Debug1("gzwrite() -> %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int Gzclose(gzFile file) {
|
||||
int result;
|
||||
Debug1("gzclose(%p)", file);
|
||||
result = gzclose(file);
|
||||
Debug1("gzclose() -> %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* WITH_GZIP */
|
||||
|
||||
#endif /* WITH_SYCLS */
|
||||
|
|
21
sycls.h
21
sycls.h
|
@ -75,6 +75,8 @@ int Chmod(const char *path, mode_t mode);
|
|||
int Poll(struct pollfd *ufds, unsigned int nfds, int timeout);
|
||||
int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
struct timeval *timeout);
|
||||
int Pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
struct timespec *timeout, const sigset_t *sigmask);
|
||||
pid_t Fork(void);
|
||||
pid_t Waitpid(pid_t pid, int *status, int options);
|
||||
#ifndef HAVE_TYPE_SIGHANDLER
|
||||
|
@ -133,9 +135,13 @@ int Grantpt(int fd);
|
|||
int Unlockpt(int fd);
|
||||
int Gethostname(char *name, size_t len);
|
||||
int Uname(struct utsname *buf);
|
||||
int Sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
|
||||
int Atexit(void (*func)(void));
|
||||
void Exit(int status);
|
||||
void Abort(void);
|
||||
int Pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||
void *(*start_routine)(void *), void *arg);
|
||||
int Pthread_join(pthread_t thread, void **value_ptr);
|
||||
int Mkstemp(char *template);
|
||||
|
||||
char *Readline(const char *prompt);
|
||||
|
@ -145,6 +151,12 @@ int Write_history(const char *filename);
|
|||
int Append_history(int nelements, const char *filename);
|
||||
int Read_history(const char *filename);
|
||||
void Add_history(const char *string);
|
||||
#if WITH_GZIP
|
||||
gzFile Gzdopen(int fd, const char *mode) {
|
||||
int Gzread(gzFile file, voidp buf, unsigned len) {
|
||||
int Gzwrite(gzFile file, const voidp buf, unsigned len) {
|
||||
int Gzclose(gzFile file) {
|
||||
#endif /* WITH_GZIP */
|
||||
|
||||
#else /* !WITH_SYCLS */
|
||||
|
||||
|
@ -205,6 +217,7 @@ void Add_history(const char *string);
|
|||
#define Chmod(p,m) chmod(p,m)
|
||||
#define Poll(u, n, t) poll(u, n, t)
|
||||
#define Select(n,r,w,e,t) select(n,r,w,e,t)
|
||||
#define Pselect(n,r,w,e,t,s) select(n,r,w,e,t,s)
|
||||
#define Fork() fork()
|
||||
#define Waitpid(p,s,o) waitpid(p,s,o)
|
||||
#define Signal(s,h) signal(s,h)
|
||||
|
@ -252,9 +265,12 @@ void Add_history(const char *string);
|
|||
#define Getpgid(p) getpgid(p)
|
||||
#define Gethostname(n,l) gethostname(n,l)
|
||||
#define Uname(b) uname(b)
|
||||
#define Sigprocmask(h,s,o) sigprocmask(h,s,o)
|
||||
#define Atexit(f) atexit(f)
|
||||
#define Exit(s) exit(s)
|
||||
#define Abort() abort()
|
||||
#define Pthread_create(t,attr,s,arg) pthread_create(t,attr,s,arg)
|
||||
#define Pthread_join(t,ptr) pthread_join(t,ptr)
|
||||
#define Mkstemp(t) mkstemp(t)
|
||||
|
||||
#define Readline(p) readline(p)
|
||||
|
@ -265,6 +281,11 @@ void Add_history(const char *string);
|
|||
#define Read_history(f) read_history(f)
|
||||
#define Add_history(s) add_history(s)
|
||||
|
||||
#define Gzdopen(f,m) gzdopen(f,m)
|
||||
#define Gzread(f,b,l) gzread(f,b,l)
|
||||
#define Gzwrite(f,b,l) gzwrite(f,b,l)
|
||||
#define Gzclose(f) gzclose(f)
|
||||
|
||||
#endif /* !WITH_SYCLS */
|
||||
|
||||
#endif /* !defined(__sycls_h_included) */
|
||||
|
|
|
@ -67,10 +67,11 @@
|
|||
#if HAVE_FCNTL_H
|
||||
#include <fcntl.h> /* open(), O_RDWR */
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#if HAVE_NETDB_H && (_WITH_IP4 || _WITH_IP6)
|
||||
#include <netdb.h> /* struct hostent, gethostbyname() */
|
||||
#endif
|
||||
#if HAVE_SYS_UN_H && WITH_UNIX
|
||||
#if HAVE_SYS_UN_H && _WITH_UNIX
|
||||
#include <sys/un.h> /* struct sockaddr_un, unix domain sockets */
|
||||
#endif
|
||||
#if HAVE_SYS_IOCTL_H
|
||||
|
|
|
@ -402,7 +402,7 @@ const char *hstrerror(int err) {
|
|||
#endif /* !HAVE_HSTRERROR */
|
||||
|
||||
|
||||
#if WITH_TCP || WITH_UDP
|
||||
#if _WITH_TCP || _WITH_UDP
|
||||
/* returns port in network byte order */
|
||||
int parseport(const char *portname, int ipproto) {
|
||||
struct servent *se;
|
||||
|
@ -425,7 +425,7 @@ int parseport(const char *portname, int ipproto) {
|
|||
|
||||
return se->s_port;
|
||||
}
|
||||
#endif /* WITH_TCP || WITH_UDP */
|
||||
#endif /* _WITH_TCP || _WITH_UDP */
|
||||
|
||||
#if WITH_IP4 || WITH_IP6
|
||||
/* check the systems interfaces for ifname and return its index
|
||||
|
|
12
sysutils.h
12
sysutils.h
|
@ -17,15 +17,15 @@ union xioin6_u {
|
|||
|
||||
union sockaddr_union {
|
||||
struct sockaddr soa;
|
||||
#if WITH_UNIX
|
||||
#if _WITH_UNIX
|
||||
struct sockaddr_un un;
|
||||
#endif /* WITH_UNIX */
|
||||
#if WITH_IP4
|
||||
#endif /* _WITH_UNIX */
|
||||
#if _WITH_IP4
|
||||
struct sockaddr_in ip4;
|
||||
#endif /* WITH_IP4 */
|
||||
#if WITH_IP6
|
||||
#endif /* _WITH_IP4 */
|
||||
#if _WITH_IP6
|
||||
struct sockaddr_in6 ip6;
|
||||
#endif /* WITH_IP6 */
|
||||
#endif /* _WITH_IP6 */
|
||||
} ;
|
||||
|
||||
#if _WITH_IP4
|
||||
|
|
429
test.sh
429
test.sh
|
@ -25,7 +25,7 @@ export SOCAT_OPTS="$opts"
|
|||
#debug="1"
|
||||
debug=
|
||||
TESTS="$@"
|
||||
INTERFACE=eth0; # not used for function tests
|
||||
INTERFACE=eth1; # not used for function tests
|
||||
MCINTERFACE=lo # !!! Linux only
|
||||
#LOCALHOST=192.168.58.1
|
||||
#LOCALHOST=localhost
|
||||
|
@ -45,6 +45,16 @@ if ! type usleep >/dev/null 2>&1; then
|
|||
sleep $(((n+999999)/1000000))
|
||||
}
|
||||
fi
|
||||
|
||||
# a "real value" sleep
|
||||
rsleep () {
|
||||
local n="$1"
|
||||
local s="${n%.*}"
|
||||
local u="${n#*.}"
|
||||
sleep "$s"
|
||||
usleep "$((u*10**(6-${#u})))"
|
||||
}
|
||||
|
||||
#USLEEP=usleep
|
||||
F_n="%3d" # format string for test numbers
|
||||
LANG=C
|
||||
|
@ -89,7 +99,7 @@ esac
|
|||
# for some tests we need a second local IPv4 address
|
||||
case "$UNAME" in
|
||||
Linux)
|
||||
BROADCASTIF=eth0
|
||||
BROADCASTIF=eth1
|
||||
SECONDADDR=127.0.0.2
|
||||
BCADDR=127.255.255.255
|
||||
BCIFADDR=$($IFCONFIG $BROADCASTIF |grep 'inet ' |awk '{print($2);}' |cut -d: -f2) ;;
|
||||
|
@ -124,7 +134,7 @@ case "$UNAME" in
|
|||
esac
|
||||
if [ -z "$SECONDIP6ADDR" ]; then
|
||||
case "$TESTS" in
|
||||
*%root2%*) $IFCONFIG eth0 ::2/128
|
||||
*%root2%*) $IFCONFIG eth1 ::2/128
|
||||
esac
|
||||
fi
|
||||
|
||||
|
@ -468,7 +478,7 @@ N=1
|
|||
#for o in $(filloptionvalues $OPTS|tr ',' ' '); do
|
||||
# echo testing if $METHOD accepts option $o
|
||||
# touch $TF
|
||||
# $SOCAT $opts -!!$method:$TF,$o /dev/null,ignoreof </dev/null
|
||||
# $SOCAT $opts $method:$TF,$o%- /dev/null,ignoreof </dev/null
|
||||
# rm -f $TF
|
||||
#done
|
||||
|
||||
|
@ -971,7 +981,7 @@ for addr in create; do
|
|||
for o in $(filloptionvalues $OPTS|tr ',' ' '); do
|
||||
echo testing if $ADDR accepts option $o
|
||||
rm -f $TF
|
||||
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null
|
||||
$SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
|
||||
rm -f $TF
|
||||
done
|
||||
done
|
||||
|
@ -1099,7 +1109,7 @@ for addr in open; do
|
|||
for o in $(filloptionvalues $OPTS|tr ',' ' '); do
|
||||
echo testing if $ADDR on file accepts option $o
|
||||
touch $TF
|
||||
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null
|
||||
$SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
|
||||
rm -f $TF
|
||||
done
|
||||
done
|
||||
|
@ -1129,7 +1139,7 @@ for addr in gopen; do
|
|||
for o in $(filloptionvalues $OPTS|tr ',' ' '); do
|
||||
echo testing if $ADDR on new file accepts option $o
|
||||
rm -f $TF
|
||||
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null
|
||||
$SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
|
||||
rm -f $TF
|
||||
done
|
||||
|
||||
|
@ -1147,7 +1157,7 @@ for addr in gopen; do
|
|||
for o in $(filloptionvalues $OPTS|tr ',' ' '); do
|
||||
echo testing if $ADDR on existing file accepts option $o
|
||||
rm -f $TF; touch $TF
|
||||
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null
|
||||
$SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
|
||||
rm -f $TF
|
||||
done
|
||||
|
||||
|
@ -1183,7 +1193,7 @@ for addr in gopen; do
|
|||
for o in $(filloptionvalues $OPTS|tr ',' ' '); do
|
||||
echo testing if $ADDR on socket accepts option $o
|
||||
rm -f $TF; $SOCAT - UNIX-L:$TF & pid=$!
|
||||
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null
|
||||
$SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
|
||||
kill $pid 2>/dev/null
|
||||
rm -f $TF
|
||||
done
|
||||
|
@ -1203,7 +1213,7 @@ for addr in gopen; do
|
|||
for o in $(filloptionvalues $OPTS|tr ',' ' '); do
|
||||
echo testing if $ADDR on existing device accepts option $o
|
||||
rm -f $TF; mknod $TF c 1 3
|
||||
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null
|
||||
$SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
|
||||
done
|
||||
else
|
||||
TEST="$ADDR on existing device accepts all its options"
|
||||
|
@ -1219,7 +1229,7 @@ for addr in gopen; do
|
|||
#echo $OPTS
|
||||
for o in $(filloptionvalues $OPTS|tr ',' ' '); do
|
||||
echo testing if $ADDR on existing device accepts option $o
|
||||
$SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof </dev/null
|
||||
$SOCAT $opts $addr:$TF,$o%- /dev/null,ignoreof </dev/null
|
||||
done
|
||||
fi
|
||||
|
||||
|
@ -1425,7 +1435,7 @@ testecho () {
|
|||
local arg1="$3"; [ -z "$arg1" ] && arg1="-"
|
||||
local arg2="$4"; [ -z "$arg2" ] && arg2="echo"
|
||||
local opts="$5"
|
||||
local T="$6"; [ -z "$T" ] && T=0
|
||||
local T="$6"; [ -z "$T" ] && T=0; export T
|
||||
local tf="$td/test$N.stdout"
|
||||
local te="$td/test$N.stderr"
|
||||
local tdiff="$td/test$N.diff"
|
||||
|
@ -1435,7 +1445,7 @@ testecho () {
|
|||
$PRINTF "test $F_n %s... " $num "$title"
|
||||
#echo "$da" |$cmd >"$tf" 2>"$te"
|
||||
#set -vx
|
||||
(echo "$da"; sleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" &
|
||||
(echo "$da"; rsleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" &
|
||||
export rc1=$!
|
||||
#sleep 5 && kill $rc1 2>/dev/null &
|
||||
# rc2=$!
|
||||
|
@ -1461,6 +1471,44 @@ testecho () {
|
|||
fi
|
||||
}
|
||||
|
||||
|
||||
# special function for use with the test address of socat V2 chains
|
||||
testchain () {
|
||||
local num="$1"
|
||||
local title="$2"
|
||||
local arg1="$3"; [ -z "$arg1" ] && arg1="-"
|
||||
local arg2="$4"; [ -z "$arg2" ] && arg2="echo"
|
||||
local opts="$5"
|
||||
local suffix="$6" # what is to be appended by tests
|
||||
local T="$7"; [ -z "$T" ] && T=0; export T
|
||||
local tf="$td/test$N.stdout"
|
||||
local te="$td/test$N.stderr"
|
||||
local tdiff="$td/test$N.diff"
|
||||
local da="$(date)"
|
||||
$PRINTF "test $F_n %s... " $num "$title"
|
||||
(echo "$da"; rsleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" &
|
||||
export rc1=$!
|
||||
wait $rc1
|
||||
if [ "$?" != 0 ]; then
|
||||
$PRINTF "$FAILED: $SOCAT:\n"
|
||||
echo "$SOCAT $opts $arg1 $arg2"
|
||||
cat "$te"
|
||||
numFAIL=$((numFAIL+1))
|
||||
elif echo -e "$da\n$suffix\c" |diff - "$tf" >"$tdiff" 2>&1; then
|
||||
$PRINTF "$OK\n"
|
||||
if [ -n "$debug" ]; then cat $te; fi
|
||||
numOK=$((numOK+1))
|
||||
else
|
||||
$PRINTF "$FAILED:\n"
|
||||
echo "$SOCAT $opts $arg1 $arg2"
|
||||
cat "$te"
|
||||
echo diff:
|
||||
cat "$tdiff"
|
||||
numFAIL=$((numFAIL+1))
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# test if call to od and throughput of data works - with graceful shutdown and
|
||||
# flush of od buffers
|
||||
testod () {
|
||||
|
@ -1469,14 +1517,14 @@ testod () {
|
|||
local arg1="$3"; [ -z "$arg1" ] && arg1="-"
|
||||
local arg2="$4"; [ -z "$arg2" ] && arg2="echo"
|
||||
local opts="$5"
|
||||
local T="$6"; [ -z "$T" ] && T=0
|
||||
local T="$6"; [ -z "$T" ] && T=0; export T
|
||||
local tf="$td/test$N.stdout"
|
||||
local te="$td/test$N.stderr"
|
||||
local tdiff="$td/test$N.diff"
|
||||
local dain="$(date)"
|
||||
local daout="$(echo "$dain" |od -c)"
|
||||
$PRINTF "test $F_n %s... " $num "$title"
|
||||
(echo "$dain"; sleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te"
|
||||
(echo "$dain"; rsleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te"
|
||||
if [ "$?" != 0 ]; then
|
||||
$PRINTF "$FAILED: $SOCAT:\n"
|
||||
echo "$SOCAT $opts $arg1 $arg2"
|
||||
|
@ -1816,17 +1864,20 @@ gentestcert () {
|
|||
local name="$1"
|
||||
if [ -f $name.key -a -f $name.crt -a -f $name.pem ]; then return; fi
|
||||
openssl genrsa $OPENSSL_RAND -out $name.key 768 >/dev/null 2>&1
|
||||
openssl req -new -config testcert.conf -key $name.key -x509 -out $name.crt >/dev/null 2>&1
|
||||
openssl req -new -config testcert.conf -key $name.key -x509 -days 3653 -out $name.crt >/dev/null 2>&1
|
||||
cat $name.key $name.crt >$name.pem
|
||||
}
|
||||
|
||||
# generate a test DSA key and certificate
|
||||
gentestdsacert () {
|
||||
#set -vx
|
||||
local name="$1"
|
||||
if [ -f $name.key -a -f $name.crt -a -f $name.pem ]; then return; fi
|
||||
if [ -f $name.key -a -f $name.crt -a -f $name.pem ]; then
|
||||
return;
|
||||
fi
|
||||
openssl dsaparam -out $name-dsa.pem 512 >/dev/null 2>&1
|
||||
openssl dhparam -dsaparam -out $name-dh.pem 512 >/dev/null 2>&1
|
||||
openssl req -newkey dsa:$name-dsa.pem -keyout $name.key -nodes -x509 -config testcert.conf -out $name.crt >/dev/null 2>&1
|
||||
openssl req -newkey dsa:$name-dsa.pem -keyout $name.key -nodes -x509 -days 3653 -config testcert.conf -out $name.crt >/dev/null 2>&1
|
||||
cat $name-dsa.pem $name-dh.pem $name.key $name.crt >$name.pem
|
||||
}
|
||||
|
||||
|
@ -1861,8 +1912,8 @@ N=$((N+1))
|
|||
NAME=DUALSTDIO
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%stdio%*|*%$NAME%*)
|
||||
TEST="$NAME: splitted form of stdio ('stdin!!stdout') with simple echo via internal pipe"
|
||||
testecho "$N" "$TEST" "stdin!!stdout" "pipe" "$opts"
|
||||
TEST="$NAME: splitted form of stdio ('stdout%stdin') with simple echo via internal pipe"
|
||||
testecho "$N" "$TEST" "stdout%stdin" "pipe" "$opts"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
@ -1870,8 +1921,8 @@ N=$((N+1))
|
|||
NAME=DUALSHORTSTDIO
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%stdio%*|*%$NAME%*)
|
||||
TEST="$NAME: short splitted form of stdio ('-!!-') with simple echo via internal pipe"
|
||||
testecho "$N" "$TEST" "-!!-" "pipe" "$opts"
|
||||
TEST="$NAME: short splitted form of stdio ('-%-') with simple echo via internal pipe"
|
||||
testecho "$N" "$TEST" "-%-" "pipe" "$opts"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
@ -1880,7 +1931,7 @@ NAME=DUALFDS
|
|||
case "$TESTS" in
|
||||
*%functions%*|*%fd%*|*%$NAME%*)
|
||||
TEST="$NAME: file descriptors with simple echo via internal pipe"
|
||||
testecho "$N" "$TEST" "0!!1" "pipe" "$opts"
|
||||
testecho "$N" "$TEST" "1%0" "pipe" "$opts"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
@ -1897,14 +1948,15 @@ esac
|
|||
N=$((N+1))
|
||||
|
||||
|
||||
NAME=DUALPIPE
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%pipe%*|*%$NAME%*)
|
||||
TEST="$NAME: simple echo via named pipe, specified twice"
|
||||
tp="$td/pipe$N"
|
||||
testecho "$N" "$TEST" "" "pipe:$tp,nonblock!!pipe:$tp" "$opts"
|
||||
esac
|
||||
N=$((N+1))
|
||||
# does not work with <write>%<read>
|
||||
#NAME=DUALPIPE
|
||||
#case "$TESTS" in
|
||||
#*%functions%*|*%pipe%*|*%$NAME%*)
|
||||
#TEST="$NAME: simple echo via named pipe, specified twice"
|
||||
#tp="$td/pipe$N"
|
||||
#testecho "$N" "$TEST" "" "pipe:$tp%pipe:$tp,nonblock" "$opts"
|
||||
#esac
|
||||
#N=$((N+1))
|
||||
|
||||
|
||||
NAME=FILE
|
||||
|
@ -1912,7 +1964,7 @@ case "$TESTS" in
|
|||
*%functions%*|*%file%*|*%ignoreeof%*|*%$NAME%*)
|
||||
TEST="$NAME: simple echo via file"
|
||||
tf="$td/file$N"
|
||||
testecho "$N" "$TEST" "" "$tf,ignoreeof!!$tf" "$opts"
|
||||
testecho "$N" "$TEST" "" "$tf%$tf,ignoreeof" "$opts"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
@ -1994,7 +2046,8 @@ NAME=DUALSYSTEMFDS
|
|||
case "$TESTS" in
|
||||
*%functions%*|*%system%*|*%$NAME%*)
|
||||
TEST="$NAME: echo via dual system() of cat"
|
||||
testecho "$N" "$TEST" "system:$CAT>&6,fdout=6!!system:$CAT<&7,fdin=7" "" "$opts"
|
||||
#testecho "$N" "$TEST" "system:'strace -tt -o /tmp/cat.out cat'>&6,fdout=6!!system:$CAT<&7,fdin=7" "" "$opts" "$T"
|
||||
testecho "$N" "$TEST" "system:$CAT<&7,fdin=7%system:'cat'>&6,fdout=6" "" "$opts" "0.1"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
@ -2003,7 +2056,7 @@ NAME=EXECSOCKETFLUSH
|
|||
case "$TESTS" in
|
||||
*%functions%*|*%exec%*|*%$NAME%*)
|
||||
TEST="$NAME: call to od via exec with socketpair"
|
||||
testod "$N" "$TEST" "" "exec:$OD_C" "$opts"
|
||||
testod "$N" "$TEST" "" "exec:$OD_C" "$opts" "0.1"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
@ -2012,7 +2065,7 @@ NAME=SYSTEMSOCKETFLUSH
|
|||
case "$TESTS" in
|
||||
*%functions%*|*%system%*|*%$NAME%*)
|
||||
TEST="$NAME: call to od via system() with socketpair"
|
||||
testod "$N" "$TEST" "" "system:$OD_C" "$opts"
|
||||
testod "$N" "$TEST" "" "system:$OD_C" "$opts" "0.1"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
@ -2081,7 +2134,7 @@ N=$((N+1))
|
|||
#case "$TESTS" in
|
||||
#*%functions%*|*%system%*|*%$NAME%*)
|
||||
#TEST="$NAME: call to od via dual system()"
|
||||
#testecho "$N" "$TEST" "system:$OD_C>&6,fdout=6!!system:$CAT<&7,fdin=7" "" "$opts"
|
||||
#testecho "$N" "$TEST" "system:$CAT<&7,fdin=7%system:$OD_C>&6,fdout=6" "" "$opts"
|
||||
#esac
|
||||
#N=$((N+1))
|
||||
|
||||
|
@ -2227,7 +2280,7 @@ TEST="$NAME: echo via two unidirectional UDP IPv4 sockets"
|
|||
tf="$td/file$N"
|
||||
p1=$PORT
|
||||
p2=$((PORT+1))
|
||||
testecho "$N" "$TEST" "" "udp:127.0.0.1:$p2,sp=$p1!!udp:127.0.0.1:$p1,sp=$p2" "$opts"
|
||||
testecho "$N" "$TEST" "" "udp:127.0.0.1:$p1,sp=$p2%udp:127.0.0.1:$p2,sp=$p1" "$opts"
|
||||
esac
|
||||
PORT=$((PORT+2))
|
||||
N=$((N+1))
|
||||
|
@ -2248,7 +2301,7 @@ ts="$td/test$N.socket"
|
|||
tdiff="$td/test$N.diff"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts UNIX-LISTEN:$ts PIPE"
|
||||
CMD2="$SOCAT $opts -!!- UNIX:$ts"
|
||||
CMD2="$SOCAT $opts -%- UNIX:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD1 </dev/null >$tf 2>"${te}1" &
|
||||
bg=$! # background process id
|
||||
|
@ -2285,7 +2338,7 @@ tsl=$PORT
|
|||
ts="127.0.0.1:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts TCP4-LISTEN:$tsl,reuseaddr PIPE"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD1 >"$tf" 2>"${te}1" &
|
||||
waittcp4port $tsl 1
|
||||
|
@ -2325,7 +2378,7 @@ tsl=$PORT
|
|||
ts="[::1]:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts TCP6-listen:$tsl,reuseaddr PIPE"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP6:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD1 >"$tf" 2>"${te}1" &
|
||||
pid=$! # background process id
|
||||
|
@ -2371,7 +2424,7 @@ tsl=$PORT
|
|||
ts="127.0.0.1:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts TCP-listen:$tsl,pf=ip4,reuseaddr PIPE"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD1 >"$tf" 2>"${te}1" &
|
||||
pid=$! # background process id
|
||||
|
@ -2417,7 +2470,7 @@ tsl=$PORT
|
|||
ts="[::1]:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts TCP-listen:$tsl,pf=ip6,reuseaddr PIPE"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD1 >"$tf" 2>"${te}1" &
|
||||
pid=$! # background process id
|
||||
|
@ -2465,7 +2518,7 @@ tsl=$PORT
|
|||
ts="127.0.0.1:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts TCP6-listen:$tsl,ipv6-v6only=0,reuseaddr PIPE"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD1 >"$tf" 2>"${te}1" &
|
||||
pid=$! # background process id
|
||||
|
@ -2513,7 +2566,7 @@ tsl=$PORT
|
|||
ts="127.0.0.1:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts TCP6-listen:$tsl,ipv6-v6only=1,reuseaddr PIPE"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD1 >"$tf" 2>"${te}1" &
|
||||
pid=$! # background process id
|
||||
|
@ -2558,7 +2611,7 @@ tsl=$PORT
|
|||
ts="127.0.0.1:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts TCP-listen:$tsl,reuseaddr PIPE"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" &
|
||||
pid=$! # background process id
|
||||
|
@ -2603,7 +2656,7 @@ tsl=$PORT
|
|||
ts="[::1]:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts TCP-listen:$tsl,reuseaddr PIPE"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP6:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" &
|
||||
pid=$! # background process id
|
||||
|
@ -2651,7 +2704,7 @@ tsl=$PORT
|
|||
ts="127.0.0.1:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts -4 TCP-listen:$tsl,reuseaddr PIPE"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" &
|
||||
pid=$! # background process id
|
||||
|
@ -2696,7 +2749,7 @@ tsl=$PORT
|
|||
ts="[::1]:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts -6 TCP-listen:$tsl,reuseaddr PIPE"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP6:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" &
|
||||
pid=$! # background process id
|
||||
|
@ -2745,7 +2798,7 @@ tsl=$PORT
|
|||
ts="127.0.0.1:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts -6 TCP-listen:$tsl,pf=ip4,reuseaddr PIPE"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" &
|
||||
pid=$! # background process id
|
||||
|
@ -2790,7 +2843,7 @@ tsl=$PORT
|
|||
ts="[::1]:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts -4 TCP-listen:$tsl,pf=ip6,reuseaddr PIPE"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP6:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" &
|
||||
pid=$! # background process id
|
||||
|
@ -2915,7 +2968,7 @@ te="$td/test$N.stderr"
|
|||
tdiff="$td/test$N.diff"
|
||||
da=$(date)
|
||||
echo "$da" >$tf1
|
||||
CMD="$SOCAT $opts $tf1!!/dev/null /dev/null,ignoreeof!!-"
|
||||
CMD="$SOCAT $opts /dev/null%$tf1 -%/dev/null,ignoreeof"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD >"$tf2" 2>"$te"
|
||||
if [ $? -ne 0 ]; then
|
||||
|
@ -2945,7 +2998,7 @@ tf="$td/test$N.stdout"
|
|||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da=$(date)
|
||||
CMD="$SOCAT $opts $tp!!/dev/null /dev/null,ignoreeof!!$tf"
|
||||
CMD="$SOCAT $opts /dev/null%$tp $tf%/dev/null,ignoreeof"
|
||||
printf "test $F_n $TEST... " $N
|
||||
#mknod $tp p # no mknod p on FreeBSD
|
||||
mkfifo $tp
|
||||
|
@ -3121,9 +3174,9 @@ case "$TESTS" in
|
|||
TEST="$NAME: exec against address with ignoreeof"
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
CMD="$SOCAT $opts -lf /dev/null EXEC:$TRUE /dev/null,ignoreeof"
|
||||
CMD="$SOCAT $opts -lf "$te" EXEC:$TRUE /dev/null,ignoreeof"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD >"$tf" 2>"$te"
|
||||
$CMD >"$tf"
|
||||
if [ -s "$te" ]; then
|
||||
$PRINTF "$FAILED: $SOCAT:\n"
|
||||
echo "$CMD"
|
||||
|
@ -3337,6 +3390,119 @@ esac
|
|||
N=$((N+1))
|
||||
|
||||
|
||||
NAME=CHAIN
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%$NAME%*)
|
||||
TEST="$NAME: stdio to test+pipe"
|
||||
testchain "$N" "$TEST" "stdio" "test|pipe" "$opts" "><"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
NAME=REVCHAIN
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%$NAME%*)
|
||||
TEST="$NAME: stdio to rev.test+pipe"
|
||||
testchain "$N" "$TEST" "stdio" "^test|pipe" "$opts" "<>"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
NAME=TWOCHAINS
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%$NAME%*)
|
||||
TEST="$NAME: test+stdio vs. test+pipe"
|
||||
testchain "$N" "$TEST" "test|stdio" "test|pipe" "$opts" "<><>"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
NAME=TWOREVCHAINS
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%$NAME%*)
|
||||
TEST="$NAME: rev.test+stdio vs. rev.test+pipe"
|
||||
testchain "$N" "$TEST" "^test|stdio" "^test|pipe" "$opts" "><><"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
NAME=LONGCHAIN
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%$NAME%*)
|
||||
TEST="$NAME: stdio vs. four-tests+pipe"
|
||||
testchain "$N" "$TEST" "stdio" "test|^test|test|^test|pipe" "$opts" "><><><><"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
NAME=TOWLONGCHAINS
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%$NAME%*)
|
||||
TEST="$NAME: four-tests+stdio vs. four-tests+pipe"
|
||||
testchain "$N" "$TEST" "^test|test|^test|test|stdio" "test|^test|test|^test|pipe" "$opts" "<><>><><><><<><>"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
NAME=CHAINSPACES
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%$NAME%*)
|
||||
TEST="$NAME: lot of test with spaces"
|
||||
testchain "$N" "$TEST" " ^ test | test | ^ test | test | stdio " " test | ^ test | test | ^ test | pipe " "$opts" "<><>><><><><<><>"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
NAME=CHAINUNIDIR
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%$NAME%*)
|
||||
TEST="$NAME: two unidirectional chains"
|
||||
testchain "$N" "$TEST" "test|stdin" "test|stdout" "-u $opts" "<>"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
NAME=CHAINREVDIR
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%$NAME%*)
|
||||
TEST="$NAME: two unidirectional chains, right to left"
|
||||
testchain "$N" "$TEST" "^test|stdout" "^test|stdin" "-U $opts" "><"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
NAME=CHAINDUAL
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%dual%*|*%$NAME%*)
|
||||
TEST="$NAME: bidirectional dual chain (uni/rev)"
|
||||
testchain "$N" "$TEST" "stdio" "testuni%testrev|pipe" "$opts" "><"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
NAME=CHAINDUAL2
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%dual%*|*%$NAME%*)
|
||||
TEST="$NAME: bidirectional dual chain (bi/rev)"
|
||||
testchain "$N" "$TEST" "stdio" "test%testrev|pipe" "$opts" "><"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
NAME=CHAINDUAL3
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%dual%*|*%$NAME%*)
|
||||
TEST="$NAME: bidirectional dual chain (uni/bi)"
|
||||
testchain "$N" "$TEST" "stdio" "testuni%^test|pipe" "$opts" "><"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
NAME=CHAINDUAL4
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%dual%*|*%$NAME%*)
|
||||
TEST="$NAME: bidirectional dual chain (bi/bi)"
|
||||
testchain "$N" "$TEST" "stdio" "test%^test|pipe" "$opts" "><"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
NAME=CHAINDUAL5
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%chain%*|*%dual%*|*%$NAME%*)
|
||||
TEST="$NAME: bidirectional mixed normal and dual chains"
|
||||
testchain "$N" "$TEST" "test|test%^test|^test|stdio" "^test|testuni%testrev|test|pipe" "$opts" "><<<>><<>>><"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
||||
NAME=OPENSSL_TCP4
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
|
||||
|
@ -3358,12 +3524,15 @@ tdiff="$td/test$N.diff"
|
|||
da=$(date)
|
||||
CMD2="$SOCAT $opts exec:'openssl s_server -accept "$PORT" -quiet -cert testsrv.pem' pipe"
|
||||
#! CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT"
|
||||
CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD"
|
||||
#CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD"
|
||||
CMD="$SOCAT $opts - openssl,verify=0,$SOCAT_EGD|tcp4:$LOCALHOST:$PORT"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval "$CMD2 2>\"${te}1\" &"
|
||||
pid=$! # background process id
|
||||
waittcp4port $PORT
|
||||
echo "$da" |$CMD >$tf 2>"${te}2"
|
||||
# the openssl s_server program appears to not support half closed connections,
|
||||
# so we must delay EOF
|
||||
(echo "$da"; sleep 1) |$CMD >$tf 2>"${te}2"
|
||||
if ! echo "$da" |diff - "$tf" >"$tdiff"; then
|
||||
$PRINTF "$FAILED: $SOCAT:\n"
|
||||
echo "$CMD2 &"
|
||||
|
@ -3401,8 +3570,10 @@ tf="$td/test$N.stdout"
|
|||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da=$(date)
|
||||
CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe"
|
||||
CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD"
|
||||
#CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe"
|
||||
CMD2="$SOCAT $opts TCP4-LISTEN:$PORT,reuseaddr ^OPENSSL-LISTEN,$SOCAT_EGD',cert=testsrv.crt,key=testsrv.key,verify=0|pipe'"
|
||||
#CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,,verify=0,$SOCAT_EGD"
|
||||
CMD="$SOCAT $opts - openssl,verify=0,$SOCAT_EGD|tcp4:$LOCALHOST:$PORT"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval "$CMD2 2>\"${te}1\" &"
|
||||
pid=$! # background process id
|
||||
|
@ -3625,7 +3796,8 @@ tdiff="$td/test$N.diff"
|
|||
da="$(date)" da="$da$($ECHO '\r')"
|
||||
# we have a normal tcp echo listening - so the socks header must appear in answer
|
||||
CMD2="$SOCAT tcp4-l:$PORT,reuseaddr exec:\"./socks4echo.sh\""
|
||||
CMD="$SOCAT $opts - socks4:$LOCALHOST:32.98.76.54:32109,pf=ip4,socksport=$PORT",socksuser="nobody"
|
||||
#CMD="$SOCAT $opts - socks4:$LOCALHOST:32.98.76.54:32109,pf=ip4,socksport=$PORT",socksuser="nobody"
|
||||
CMD="$SOCAT $opts - socks4:32.98.76.54:32109,socksuser=nobody|tcp4:$LOCALHOST:$PORT"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval "$CMD2 2>\"${te}1\" &"
|
||||
pid=$! # background process id
|
||||
|
@ -3712,7 +3884,8 @@ tdiff="$td/test$N.diff"
|
|||
da="$(date)" da="$da$($ECHO '\r')"
|
||||
# we have a normal tcp echo listening - so the socks header must appear in answer
|
||||
CMD2="$SOCAT tcp4-l:$PORT,reuseaddr exec:\"./socks4a-echo.sh\""
|
||||
CMD="$SOCAT $opts - socks4a:$LOCALHOST:localhost:32109,pf=ip4,socksport=$PORT",socksuser="nobody"
|
||||
#CMD="$SOCAT $opts - socks4a:$LOCALHOST:localhost:32109,pf=ip4,socksport=$PORT",socksuser="nobody"
|
||||
CMD="$SOCAT $opts - socks4a:localhost:32109,socksuser=nobody|tcp4:$LOCALHOST:$PORT"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval "$CMD2 2>\"${te}1\" &"
|
||||
pid=$! # background process id
|
||||
|
@ -3800,7 +3973,8 @@ tdiff="$td/test$N.diff"
|
|||
da="$(date)" da="$da$($ECHO '\r')"
|
||||
#CMD2="$SOCAT tcp4-l:$PORT,crlf system:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\""
|
||||
CMD2="$SOCAT tcp4-l:$PORT,reuseaddr,crlf exec:\"/bin/bash proxyecho.sh\""
|
||||
CMD="$SOCAT $opts - proxy:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT"
|
||||
#CMD="$SOCAT $opts - proxy:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT"
|
||||
CMD="$SOCAT $opts - proxy:127.0.0.1:1000|tcp4:$LOCALHOST:$PORT"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval "$CMD2 2>\"${te}2\" &"
|
||||
pid=$! # background process id
|
||||
|
@ -3882,7 +4056,7 @@ tsl=$PORT
|
|||
ts="127.0.0.1:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts TCP4-LISTEN:$tsl,reuseaddr exec:$CAT,nofork"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP4:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
#$CMD1 >"$tf" 2>"${te}1" &
|
||||
$CMD1 >/dev/null 2>"${te}1" &
|
||||
|
@ -3944,7 +4118,7 @@ N=$((N+1))
|
|||
#da=$(date)
|
||||
#$SOCAT UDP-listen:$tsl PIPE &
|
||||
#sleep 2
|
||||
#echo "$da" |$SOCAT stdin!!stdout UDP:$ts >"$tf"
|
||||
#echo "$da" |$SOCAT stdout%stdin UDP:$ts >"$tf"
|
||||
#if [ $? -eq 0 ] && echo "$da" |diff "$tf" -; then
|
||||
# $ECHO "... test $N succeeded"
|
||||
# numOK=$((numOK+1))
|
||||
|
@ -4068,7 +4242,8 @@ tdiff="$td/test$N.diff"
|
|||
da="$(date)" da="$da$($ECHO '\r')"
|
||||
#CMD2="$SOCAT tcp-l:$PORT,crlf system:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\""
|
||||
CMD2="$SOCAT tcp4-l:$PORT,reuseaddr,crlf exec:\"/bin/bash proxyecho.sh -w 2\""
|
||||
CMD="$SOCAT $opts - proxy:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT"
|
||||
#CMD="$SOCAT $opts - proxy:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT"
|
||||
CMD="$SOCAT $opts - proxy:127.0.0.1:1000|tcp4:$LOCALHOST:$PORT"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval "$CMD2 2>\"${te}1\" &"
|
||||
pid=$! # background process id
|
||||
|
@ -4129,7 +4304,7 @@ NAME=SINGLEEXECOUTSOCKETPAIR
|
|||
case "$TESTS" in
|
||||
*%functions%*|*%$NAME%*)
|
||||
TEST="$NAME: inheritance of stdout to single exec with socketpair"
|
||||
testecho "$N" "$TEST" "-!!exec:cat" "" "$opts" 1
|
||||
testecho "$N" "$TEST" "exec:cat%-" "" "$opts" 1
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
@ -4137,7 +4312,7 @@ NAME=SINGLEEXECOUTPIPE
|
|||
case "$TESTS" in
|
||||
*%functions%*|*%$NAME%*)
|
||||
TEST="$NAME: inheritance of stdout to single exec with pipe"
|
||||
testecho "$N" "$TEST" "-!!exec:cat,pipes" "" "$opts" 1
|
||||
testecho "$N" "$TEST" "exec:cat,pipes%-" "" "$opts" 1
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
@ -4149,7 +4324,7 @@ if ! testaddrs pty >/dev/null; then
|
|||
$PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
else
|
||||
testecho "$N" "$TEST" "-!!exec:cat,pty,raw" "" "$opts" 1
|
||||
testecho "$N" "$TEST" "exec:cat,pty,raw%-" "" "$opts" 1
|
||||
fi
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
@ -4158,7 +4333,7 @@ NAME=SINGLEEXECINSOCKETPAIR
|
|||
case "$TESTS" in
|
||||
*%functions%*|*%$NAME%*)
|
||||
TEST="$NAME: inheritance of stdin to single exec with socketpair"
|
||||
testecho "$N" "$TEST" "exec:cat!!-" "" "$opts"
|
||||
testecho "$N" "$TEST" "-%exec:cat" "" "$opts"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
@ -4166,7 +4341,7 @@ NAME=SINGLEEXECINPIPE
|
|||
case "$TESTS" in
|
||||
*%functions%*|*%$NAME%*)
|
||||
TEST="$NAME: inheritance of stdin to single exec with pipe"
|
||||
testecho "$N" "$TEST" "exec:cat,pipes!!-" "" "$opts"
|
||||
testecho "$N" "$TEST" "-%exec:cat,pipes" "" "$opts"
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
@ -4178,7 +4353,7 @@ if ! testaddrs pty >/dev/null; then
|
|||
$PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
else
|
||||
testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts" $MISCDELAY
|
||||
testecho "$N" "$TEST" "-%exec:cat,pty,raw" "" "$opts" $MISCDELAY
|
||||
fi
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
@ -4191,7 +4366,7 @@ if ! testaddrs pty >/dev/null; then
|
|||
$PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
else
|
||||
testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts"
|
||||
testecho "$N" "$TEST" "-%exec:cat,pty,raw" "" "$opts"
|
||||
fi
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
@ -4217,7 +4392,7 @@ tr="$td/test$N.ref"
|
|||
tdiff="$td/test$N.diff"
|
||||
da="$(date)" da="$da$($ECHO '\r')"
|
||||
# the feature that we really want to test is in the readline.sh script:
|
||||
CMD="$SOCAT $opts open:$tpi,nonblock!!open:$tpo exec:\"./readline.sh -nh ./readline-test.sh\",pty,ctty,setsid,raw,echo=0,isig"
|
||||
CMD="$SOCAT $opts open:$tpo%open:$tpi,nonblock exec:\"./readline.sh -nh ./readline-test.sh\",pty,ctty,setsid,raw,echo=0,isig"
|
||||
#echo "$CMD" >"$ts"
|
||||
#chmod a+x "$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
|
@ -4366,10 +4541,12 @@ CMD1="$SOCAT $opts -lpserver tcp4-l:$PORT,reuseaddr,bind=$LOCALHOST echo"
|
|||
# this is the proxy in the protected network that provides a way out
|
||||
CMD2="$SOCAT $opts -lpproxy tcp4-l:$((PORT+1)),reuseaddr,bind=$LOCALHOST,fork exec:./proxy.sh"
|
||||
# this is our proxy connect wrapper in the protected network
|
||||
CMD3="$SOCAT $opts -lpwrapper tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$LOCALHOST:$((PORT+3)),pf=ip4,proxyport=$((PORT+1)),resolve"
|
||||
#CMD3="$SOCAT $opts -lpwrapper tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$LOCALHOST:$((PORT+3)),pf=ip4,proxyport=$((PORT+1)),resolve"
|
||||
CMD3="$SOCAT $opts -lpwrapper tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$((PORT+3)),resolve\\|tcp4:$LOCALHOST:$((PORT+1))"
|
||||
# this is our double client in the protected network using SSL
|
||||
#CMD4="$SOCAT $opts -lp2client ssl:$LOCALHOST:$((PORT+2)),pf=ip4,retry=10,intervall=1,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD tcp4:$LOCALHOST:$PORT"
|
||||
CMD4="$SOCAT $opts -lp2client ssl:$LOCALHOST:$((PORT+2)),pf=ip4,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD tcp4:$LOCALHOST:$PORT"
|
||||
#CMD4="$SOCAT $opts -lp2client ssl:$LOCALHOST:$((PORT+2)),pf=ip4,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD tcp4:$LOCALHOST:$PORT"
|
||||
CMD4="$SOCAT $opts -lp2client ssl,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD\|tcp4:$LOCALHOST:$((PORT+2)) tcp4:$LOCALHOST:$PORT"
|
||||
# this is the double server in the outside network
|
||||
CMD5="$SOCAT $opts -lp2server -t1 tcp4-l:$((PORT+4)),reuseaddr,bind=$LOCALHOST ssl-l:$((PORT+3)),pf=ip4,reuseaddr,bind=$LOCALHOST,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt"
|
||||
# this is the outside client that wants to use the protected server
|
||||
|
@ -4446,11 +4623,16 @@ CMD1="$SOCAT $opts -lpserver -t1 tcp4-l:$PORT,reuseaddr,bind=$LOCALHOST,fork ech
|
|||
# this is the proxy in the protected network that provides a way out
|
||||
CMD2="$SOCAT $opts -lpproxy -t1 tcp4-l:$((PORT+1)),reuseaddr,bind=$LOCALHOST,fork exec:./proxy.sh"
|
||||
# this is our proxy connect wrapper in the protected network
|
||||
CMD3="$SOCAT $opts -lpwrapper -t3 tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$LOCALHOST:$((PORT+3)),pf=ip4,proxyport=$((PORT+1)),resolve"
|
||||
#CMD3="$SOCAT $opts -lpwrapper -t3 tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$LOCALHOST:$((PORT+3)),pf=ip4,proxyport=$((PORT+1)),resolve"
|
||||
CMD3="$SOCAT $opts -lu -lpwrapper -t3 tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$((PORT+3)),resolve\\|tcp4:$LOCALHOST:$((PORT+1))"
|
||||
# this is our double client in the protected network using SSL
|
||||
CMD4="$SOCAT $opts -lp2client -t3 ssl:$LOCALHOST:$((PORT+2)),retry=10,intervall=1,cert=testcli.pem,cafile=testsrv.crt,verify,fork,$SOCAT_EGD tcp4:$LOCALHOST:$PORT"
|
||||
#CMD4="$SOCAT $opts -lp2client -t3 ssl:$LOCALHOST:$((PORT+2)),retry=10,intervall=1,cert=testcli.pem,cafile=testsrv.crt,verify,fork,$SOCAT_EGD tcp4:$LOCALHOST:$PORT"
|
||||
#CMD4="$SOCAT $opts -lu -lp2client -t3 ssl,cert=testcli.pem,cafile=testsrv.crt,fork,$SOCAT_EGD,retry=10,intervall=1\\|tcp4:$LOCALHOST:$((PORT+2)) tcp4:$LOCALHOST:$PORT"
|
||||
CMD4="$SOCAT $opts -lu -lp2client -t3 tcp4:$LOCALHOST:$((PORT+2)),fork ^ssl,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD,retry=10,intervall=1\\|tcp4:$LOCALHOST:$PORT"
|
||||
# this is the double server in the outside network
|
||||
CMD5="$SOCAT $opts -lp2server -t4 tcp4-l:$((PORT+4)),reuseaddr,bind=$LOCALHOST,fork ssl-l:$((PORT+3)),pf=ip4,reuseaddr,bind=$LOCALHOST,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt,retry=10"
|
||||
#CMD5="$SOCAT $opts -lp2server -t4 tcp4-l:$((PORT+4)),reuseaddr,bind=$LOCALHOST,fork ssl-l:$((PORT+3)),pf=ip4,reuseaddr,bind=$LOCALHOST,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt,retry=10"
|
||||
#CMD5="$SOCAT $opts -lp2server -t4 tcp4-l:$((PORT+4)),reuseaddr,bind=$LOCALHOST,fork tcp4-l:$((PORT+3)),reuseaddr,bind=$LOCALHOST,retry=10\\|ssl-l,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt"
|
||||
CMD5="$SOCAT $opts -lp2server -t4 tcp4-l:$((PORT+4)),reuseaddr,bind=$LOCALHOST,fork ssl-l,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt\\|tcp4-l:$((PORT+3)),reuseaddr,bind=$LOCALHOST,retry=10"
|
||||
# this is the outside client that wants to use the protected server
|
||||
CMD6="$SOCAT $opts -lpclient -t5 - tcp4:$LOCALHOST:$((PORT+4)),retry=3"
|
||||
printf "test $F_n $TEST... " $N
|
||||
|
@ -4594,7 +4776,9 @@ testserversec () {
|
|||
#set -vx
|
||||
# assemble address w/ security option; on dual, take read part:
|
||||
case "$arg1" in
|
||||
*!!*) arg="${arg1%!!*},$secopt1!!${arg1#*!!}" ;;
|
||||
#*!!*) arg="${arg1%!!*},$secopt1!!${arg1#*!!}" ;;
|
||||
#*%*) arg="${arg1%\%*}%${arg1#*%},$secopt1" ;;
|
||||
*%*) arg="$arg1,$secopt1" ;;
|
||||
*) arg="$arg1,$secopt1" ;;
|
||||
esac
|
||||
# start server
|
||||
|
@ -5323,8 +5507,10 @@ tf="$td/test$N.stdout"
|
|||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da=$(date)
|
||||
CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cert=$SRVCERT.pem,key=$SRVCERT.key,verify=0 pipe"
|
||||
CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD"
|
||||
#CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cert=$SRVCERT.pem,key=$SRVCERT.key,verify=0 pipe"
|
||||
CMD2="$SOCAT $opts TCP4-LISTEN:$PORT,reuseaddr ^OPENSSL-LISTEN,$SOCAT_EGD,cert=$SRVCERT.pem,key=$SRVCERT.key,verify=0\|pipe"
|
||||
#CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD"
|
||||
CMD="$SOCAT $opts - openssl,verify=0,$SOCAT_EGD|tcp4:$LOCALHOST:$PORT"
|
||||
$PRINTF "test $F_n $TEST... " $N
|
||||
eval "$CMD2 2>\"${te}1\" &"
|
||||
pid=$! # background process id
|
||||
|
@ -5690,7 +5876,7 @@ tsl=$PORT
|
|||
ts="127.0.0.1:$tsl"
|
||||
da=$(date)
|
||||
CMD1="$SOCAT $opts TCP6-listen:$tsl,reuseaddr PIPE"
|
||||
CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts"
|
||||
CMD2="$SOCAT $opts stdout%stdin TCP6:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD1 >"$tf" 2>"${te}1" &
|
||||
pid=$! # background process id
|
||||
|
@ -6250,7 +6436,7 @@ PORT2=$PORT; PORT=$((PORT+1))
|
|||
PORT3=$PORT
|
||||
# we use the forward channel (PORT1) for testing, and have a backward channel
|
||||
# (PORT2) to get the data back, so we get the classical echo behaviour
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp4-recv:$PORT1,reuseaddr!!udp4-sendto:127.0.0.1:$PORT2" "" "sp=$PORT3" "udp4-recv:$PORT2!!udp4-sendto:127.0.0.1:$PORT1" 4 udp $PORT1 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp4-sendto:127.0.0.1:$PORT2%udp4-recv:$PORT1,reuseaddr" "" "sp=$PORT3" "udp4-sendto:127.0.0.1:$PORT1%udp4-recv:$PORT2" 4 udp $PORT1 0
|
||||
fi
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
|
@ -6268,7 +6454,7 @@ PORT1=$PORT; PORT=$((PORT+1))
|
|||
PORT2=$PORT
|
||||
# we use the forward channel (PORT1) for testing, and have a backward channel
|
||||
# (PORT2) to get the data back, so we get the classical echo behaviour
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp4-recv:$PORT1,reuseaddr!!udp4-sendto:127.0.0.1:$PORT2" "" "lowport" "udp4-recv:$PORT2!!udp4-sendto:127.0.0.1:$PORT1" 4 udp $PORT1 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp4-sendto:127.0.0.1:$PORT2%udp4-recv:$PORT1,reuseaddr" "" "lowport" "udp4-sendto:127.0.0.1:$PORT1%udp4-recv:$PORT2" 4 udp $PORT1 0
|
||||
fi
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
|
@ -6286,7 +6472,7 @@ PORT1=$PORT; PORT=$((PORT+1))
|
|||
PORT2=$PORT
|
||||
# we use the forward channel (PORT1) for testing, and have a backward channel
|
||||
# (PORT2) to get the data back, so we get the classical echo behaviour
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp4-recv:$PORT1,reuseaddr!!udp4-sendto:127.0.0.1:$PORT2" "" "range=$SECONDADDR/32" "udp4-recv:$PORT2!!udp4-sendto:127.0.0.1:$PORT1" 4 udp $PORT1 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp4-sendto:127.0.0.1:$PORT2%udp4-recv:$PORT1,reuseaddr" "" "range=$SECONDADDR/32" "udp4-sendto:127.0.0.1:$PORT1%udp4-recv:$PORT2" 4 udp $PORT1 0
|
||||
fi
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
|
@ -6308,7 +6494,7 @@ $ECHO "socat: $SECONDADDR" >"$ha"
|
|||
$ECHO "ALL: ALL" >"$hd"
|
||||
# we use the forward channel (PORT1) for testing, and have a backward channel
|
||||
# (PORT2) to get the data back, so we get the classical echo behaviour
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp4-recv:$PORT1,reuseaddr!!udp4-sendto:127.0.0.1:$PORT2" "" "tcpwrap-etc=$td" "udp4-recv:$PORT2!!udp4-sendto:127.0.0.1:$PORT1" 4 udp $PORT1 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp4-sendto:127.0.0.1:$PORT2%udp4-recv:$PORT1,reuseaddr" "" "tcpwrap-etc=$td" "udp4-sendto:127.0.0.1:$PORT1%udp4-recv:$PORT2" 4 udp $PORT1 0
|
||||
fi ;; # feat
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
|
@ -6390,7 +6576,7 @@ PORT2=$PORT; PORT=$((PORT+1))
|
|||
PORT3=$PORT
|
||||
# we use the forward channel (PORT1) for testing, and have a backward channel
|
||||
# (PORT2) to get the data back, so we get the classical echo behaviour
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "sp=$PORT3" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp6-sendto:[::1]:$PORT2%udp6-recv:$PORT1,reuseaddr" "" "sp=$PORT3" "udp6-sendto:[::1]:$PORT1%udp6-recv:$PORT2" 6 udp $PORT1 0
|
||||
fi
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
|
@ -6408,7 +6594,7 @@ PORT1=$PORT; PORT=$((PORT+1))
|
|||
PORT2=$PORT
|
||||
# we use the forward channel (PORT1) for testing, and have a backward channel
|
||||
# (PORT2) to get the data back, so we get the classical echo behaviour
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "lowport" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp6-sendto:[::1]:$PORT2%udp6-recv:$PORT1,reuseaddr" "" "lowport" "udp6-sendto:[::1]:$PORT1%udp6-recv:$PORT2" 6 udp $PORT1 0
|
||||
fi
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
|
@ -6426,7 +6612,7 @@ PORT1=$PORT; PORT=$((PORT+1))
|
|||
PORT2=$PORT
|
||||
# we use the forward channel (PORT1) for testing, and have a backward channel
|
||||
# (PORT2) to get the data back, so we get the classical echo behaviour
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "range=[::2/128]" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp6-sendto:[::1]:$PORT2%udp6-recv:$PORT1,reuseaddr" "" "range=[::2/128]" "udp6-sendto:[::1]:$PORT1%udp6-recv:$PORT2" 6 udp $PORT1 0
|
||||
fi
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
|
@ -6448,7 +6634,7 @@ PORT1=$PORT; PORT=$((PORT+1))
|
|||
PORT2=$PORT
|
||||
# we use the forward channel (PORT1) for testing, and have a backward channel
|
||||
# (PORT2) to get the data back, so we get the classical echo behaviour
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "tcpwrap-etc=$td" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp6-sendto:[::1]:$PORT2%udp6-recv:$PORT1,reuseaddr" "" "tcpwrap-etc=$td" "udp6-sendto:[::1]:$PORT1%udp6-recv:$PORT2" 6 udp $PORT1 0
|
||||
fi ;; # feat
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
|
@ -6467,7 +6653,7 @@ elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then
|
|||
numCANT=$((numCANT+1))
|
||||
else
|
||||
#testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr,fork" "" "range=$SECONDADDR/32" "ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr!!udp4-sendto:127.0.0.1:$PORT" "" "range=$SECONDADDR/32" "udp4-recv:$PORT!!ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp4-sendto:127.0.0.1:$PORT%ip4-recvfrom:$PROTO,reuseaddr" "" "range=$SECONDADDR/32" "ip4-sendto:127.0.0.1:$PROTO%udp4-recv:$PORT" 4 ip $PROTO 0
|
||||
fi # not feats, not root
|
||||
esac
|
||||
PROTO=$((PROTO+1))
|
||||
|
@ -6490,7 +6676,7 @@ hd="$td/hosts.deny"
|
|||
$ECHO "socat: $SECONDADDR" >"$ha"
|
||||
$ECHO "ALL: ALL" >"$hd"
|
||||
#testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr,fork" "" "tcpwrap-etc=$td" "ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr!!udp4-sendto:127.0.0.1:$PORT" "" "tcpwrap-etc=$td" "udp4-recv:$PORT!!ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp4-sendto:127.0.0.1:$PORT%ip4-recvfrom:$PROTO,reuseaddr" "" "tcpwrap-etc=$td" "ip4-sendto:127.0.0.1:$PROTO%udp4-recv:$PORT" 4 ip $PROTO 0
|
||||
fi # not feats, not root
|
||||
esac
|
||||
PROTO=$((PROTO+1))
|
||||
|
@ -6513,7 +6699,7 @@ PROTO1=$PROTO; PROTO=$((PROTO+1))
|
|||
PROTO2=$PROTO
|
||||
# we use the forward channel (PROTO1) for testing, and have a backward channel
|
||||
# (PROTO2) to get the data back, so we get the classical echo behaviour
|
||||
testserversec "$N" "$TEST" "$opts -s" "ip4-recv:$PROTO1,reuseaddr!!ip4-sendto:127.0.0.1:$PROTO2" "" "range=$SECONDADDR/32" "ip4-recv:$PROTO2!!ip4-sendto:127.0.0.1:$PROTO1" 4 ip $PROTO1 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "ip4-sendto:127.0.0.1:$PROTO2%ip4-recv:$PROTO1,reuseaddr" "" "range=$SECONDADDR/32" "ip4-sendto:127.0.0.1:$PROTO1%ip4-recv:$PROTO2" 4 ip $PROTO1 0
|
||||
fi # not feats, not root
|
||||
esac
|
||||
PROTO=$((PROTO+1))
|
||||
|
@ -6540,7 +6726,7 @@ $ECHO "socat: $SECONDADDR" >"$ha"
|
|||
$ECHO "ALL: ALL" >"$hd"
|
||||
# we use the forward channel (PROTO1) for testing, and have a backward channel
|
||||
# (PROTO2) to get the data back, so we get the classical echo behaviour
|
||||
testserversec "$N" "$TEST" "$opts -s" "ip4-recv:$PROTO1,reuseaddr!!ip4-sendto:127.0.0.1:$PROTO2" "" "tcpwrap-etc=$td" "ip4-recv:$PROTO2!!ip4-sendto:127.0.0.1:$PROTO1" 4 ip $PROTO1 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "ip4-sendto:127.0.0.1:$PROTO2%ip4-recv:$PROTO1,reuseaddr" "" "tcpwrap-etc=$td" "ip4-sendto:127.0.0.1:$PROTO1%ip4-recv:$PROTO2" 4 ip $PROTO1 0
|
||||
fi # not feats, not root
|
||||
esac
|
||||
PROTO=$((PROTO+1))
|
||||
|
@ -6559,7 +6745,7 @@ elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then
|
|||
numCANT=$((numCANT+1))
|
||||
else
|
||||
#testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr,fork" "" "range=[::2/128]" "ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr!!udp6-sendto:[::1]:$PORT" "" "range=[::2/128]" "udp6-recv:$PORT!!ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp6-sendto:[::1]:$PORT%ip6-recvfrom:$PROTO,reuseaddr" "" "range=[::2/128]" "ip6-sendto:[::1]:$PROTO%udp6-recv:$PORT" 6 ip $PROTO 0
|
||||
fi # not feats, not root
|
||||
esac
|
||||
PROTO=$((PROTO+1))
|
||||
|
@ -6582,7 +6768,7 @@ hd="$td/hosts.deny"
|
|||
$ECHO "socat: [::2]" >"$ha"
|
||||
$ECHO "ALL: ALL" >"$hd"
|
||||
#testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr,fork" "" "tcpwrap-etc=$td" "ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr!!udp6-sendto:[::1]:$PORT" "" "tcpwrap-etc=$td" "udp6-recv:$PORT!!ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "udp6-sendto:[::1]:$PORT%ip6-recvfrom:$PROTO,reuseaddr" "" "tcpwrap-etc=$td" "ip6-sendto:[::1]:$PROTO%udp6-recv:$PORT" 6 ip $PROTO 0
|
||||
fi # not feats, not root
|
||||
esac
|
||||
PROTO=$((PROTO+1))
|
||||
|
@ -6605,7 +6791,7 @@ PROTO1=$PROTO; PROTO=$((PROTO+1))
|
|||
PROTO2=$PROTO
|
||||
# we use the forward channel (PROTO1) for testing, and have a backward channel
|
||||
# (PROTO2) to get the data back, so we get the classical echo behaviour
|
||||
testserversec "$N" "$TEST" "$opts -s" "ip6-recv:$PROTO1,reuseaddr!!ip6-sendto:[::1]:$PROTO2" "" "range=[::2/128]" "ip6-recv:$PROTO2!!ip6-sendto:[::1]:$PROTO1" 6 ip $PROTO1 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "ip6-sendto:[::1]:$PROTO2%ip6-recv:$PROTO1,reuseaddr" "" "range=[::2/128]" "ip6-sendto:[::1]:$PROTO1%ip6-recv:$PROTO2" 6 ip $PROTO1 0
|
||||
fi # not feats, not root
|
||||
esac
|
||||
PROTO=$((PROTO+1))
|
||||
|
@ -6630,7 +6816,7 @@ $ECHO "socat: [::2]" >"$ha"
|
|||
$ECHO "ALL: ALL" >"$hd"
|
||||
# we use the forward channel (PROTO1) for testing, and have a backward channel
|
||||
# (PROTO2) to get the data back, so we get the classical echo behaviour
|
||||
testserversec "$N" "$TEST" "$opts -s" "ip6-recv:$PROTO1,reuseaddr!!ip6-sendto:[::1]:$PROTO2" "" "tcpwrap-etc=$td" "ip6-recv:$PROTO2!!ip6-sendto:[::1]:$PROTO1" 6 ip $PROTO1 0
|
||||
testserversec "$N" "$TEST" "$opts -s" "ip6-sendto:[::1]:$PROTO2%ip6-recv:$PROTO1,reuseaddr" "" "tcpwrap-etc=$td" "ip6-sendto:[::1]:$PROTO1%ip6-recv:$PROTO2" 6 ip $PROTO1 0
|
||||
fi # not feats, not root
|
||||
esac
|
||||
PROTO=$((PROTO+1))
|
||||
|
@ -6836,10 +7022,27 @@ esac
|
|||
N=$((N+1))
|
||||
|
||||
|
||||
# purpose of the shut-none option is to keep a shared socket
|
||||
# open. with shared we mean that two or more processes use it. usually, when a
|
||||
# process closes a socket, it performs a shutdown procedure with half close.
|
||||
# on a shared socket, this would shutdown the socket as a whole, disabling it
|
||||
# for all processes. the shut-none option does not shutdown but close the
|
||||
# socket; this just removes the processes reference to the socket but keeps it
|
||||
# open for the other processes.
|
||||
NAME=TCP4ENDCLOSE
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%$NAME%*)
|
||||
TEST="$NAME: end-close keeps TCP V4 socket open"
|
||||
TEST="$NAME: shut-none keeps TCP V4 socket open"
|
||||
# this is how we test the shut-none option:
|
||||
# we have some tcp service (CMD3) that accepts one connection and only receives
|
||||
# date.
|
||||
# a multiplexer process (CMD) opens a connection to that service; it accepts
|
||||
# multiple connections from client processes and merges and forwards their
|
||||
# data; each client is handled in a sub process with a clone of the forwarder
|
||||
# socket.
|
||||
# two client processes connect and send data. normally, the "common" connection
|
||||
# would terminate when the first client disconnects; with the shut-none option,
|
||||
# the data of the second process also has to arrive at the target service.
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
|
@ -6848,7 +7051,7 @@ p2=$PORT
|
|||
da1a="$(date) $RANDOM"
|
||||
da1b="$(date) $RANDOM"
|
||||
CMD1="$SOCAT $opts -u - TCP4-CONNECT:$LOCALHOST:$p1"
|
||||
CMD="$SOCAT $opts -U TCP4:$LOCALHOST:$p2,end-close TCP4-LISTEN:$p1,bind=$LOCALHOST,reuseaddr,fork"
|
||||
CMD="$SOCAT $opts -U TCP4:$LOCALHOST:$p2,shut-none TCP4-LISTEN:$p1,bind=$LOCALHOST,reuseaddr,fork"
|
||||
CMD3="$SOCAT $opts -u TCP4-LISTEN:$p2,reuseaddr,bind=$LOCALHOST -"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD3 >"$tf" 2>"${te}3" &
|
||||
|
@ -6882,11 +7085,21 @@ esac
|
|||
PORT=$((PORT+1))
|
||||
N=$((N+1))
|
||||
|
||||
|
||||
# purpose: see above; here we do not test against a TCP socket but an exec'd
|
||||
# sub process (socketpair)
|
||||
NAME=EXECENDCLOSE
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%exec%*|*%$NAME%*)
|
||||
TEST="$NAME: end-close keeps EXEC child running"
|
||||
TEST="$NAME: shut-none keeps EXEC child running"
|
||||
# this is how we test the shut-none option:
|
||||
# we have a server process (CMD) that runs a program (cat); the process accepts
|
||||
# multiple connections from client processes and merges and forwards their
|
||||
# data; each client is handled in a sub process with a clone of the forwarder
|
||||
# socket.
|
||||
# two client processes connect and send data. normally, the "common" connection
|
||||
# the the cat sub process would terminate when the first client disconnects;
|
||||
# with the shut-none option, the data of the second process also has to arrive
|
||||
# at the target service.
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
ts="$td/test$N.sock"
|
||||
|
@ -6894,7 +7107,7 @@ tdiff="$td/test$N.diff"
|
|||
da1a="$(date) $RANDOM"
|
||||
da1b="$(date) $RANDOM"
|
||||
CMD1="$SOCAT $opts - UNIX-CONNECT:$ts"
|
||||
CMD="$SOCAT -t0.1 $opts EXEC:"$CAT",end-close UNIX-LISTEN:$ts,fork"
|
||||
CMD="$SOCAT -t0.1 $opts EXEC:"$CAT",shut-none,end-close UNIX-LISTEN:$ts,fork"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD 2>"${te}2" &
|
||||
pid2=$!
|
||||
|
@ -6906,16 +7119,18 @@ usleep 100000
|
|||
kill "$pid2" 2>/dev/null
|
||||
wait
|
||||
if [ $? -ne 0 ]; then
|
||||
$PRINTF "$FAILED: $SOCAT:\n"
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "$CMD1 &"
|
||||
echo "$CMD2"
|
||||
echo "$CMD"
|
||||
cat "${te}1a" "${te}1b" "${te}2"
|
||||
$PRINTF "$FAILED: $SOCAT:\n"
|
||||
numFAIL=$((numFAIL+1))
|
||||
elif ! echo -e "$da1a\n$da1b" |diff - "$tf" >"$tdiff"; then
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "$CMD1 &"
|
||||
echo "$CMD"
|
||||
cat "$tdiff"
|
||||
cat "${te}1a" "${te}1b" "${te}2"
|
||||
$PRINTF "$FAILED: $SOCAT:\n"
|
||||
numFAIL=$((numFAIL+1))
|
||||
else
|
||||
$PRINTF "$OK\n"
|
||||
if [ -n "$debug" ]; then cat "${te}1a" "${te}1b" "${te}2"; fi
|
||||
|
@ -7721,7 +7936,7 @@ to="$td/test$N.out"
|
|||
te="$td/test$N.err"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="$(date)" da="$da$($ECHO '\r')"
|
||||
CMD="$SOCAT $opts system:\"echo A; sleep 2\",readbytes=2!!- -!!/dev/null"
|
||||
CMD="$SOCAT $opts -%system:\"echo A; sleep 2\",readbytes=2 /dev/null%-"
|
||||
printf "test $F_n $TEST... " $N
|
||||
(sleep 1; echo) |eval "$CMD" >"$to" 2>"$te"
|
||||
if test -s "$to"; then
|
||||
|
|
20
xio-creat.c
20
xio-creat.c
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xio-creat.c,v 1.16 2006/07/13 06:39:01 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* $Id: xio-creat.c,v 1.16.2.1 2006/07/24 19:17:32 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for opening addresses of create type */
|
||||
|
@ -17,8 +17,11 @@ static int xioopen_creat(int arg, const char *argv[], struct opt *opts, int rw,
|
|||
|
||||
|
||||
/*! within stream model, this is a write-only address - use 2 instead of 3 */
|
||||
const struct addrdesc addr_creat = { "create", 3, xioopen_creat, GROUP_FD|GROUP_NAMED|GROUP_FILE, 0, 0, 0 HELP(":<filename>") };
|
||||
|
||||
static const struct xioaddr_endpoint_desc xioaddr_creat1 = { XIOADDR_SYS, "create", 1, XIOBIT_ALL/*?*/, GROUP_FD|GROUP_NAMED|GROUP_FILE, XIOSHUT_NONE, XIOCLOSE_CLOSE, xioopen_creat, 0, 0, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_creat[] = {
|
||||
(union xioaddr_desc *)&xioaddr_creat1,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* retrieve the mode option and perform the creat() call.
|
||||
returns the file descriptor or a negative value. */
|
||||
|
@ -60,15 +63,16 @@ static int xioopen_creat(int argc, const char *argv[], struct opt *opts, int xio
|
|||
Notice2("creating regular file \"%s\" for %s", filename, ddirection[rw]);
|
||||
if ((result = _xioopen_creat(filename, rw, opts)) < 0)
|
||||
return result;
|
||||
fd->stream.fd = result;
|
||||
fd->stream.fd1 = fd->stream.fd2 = result;
|
||||
fd->stream.fdtype = FDTYPE_SINGLE;
|
||||
|
||||
applyopts_named(filename, opts, PH_PASTOPEN);
|
||||
if ((result = applyopts2(fd->stream.fd, opts, PH_PASTOPEN, PH_LATE2)) < 0)
|
||||
if ((result = applyopts2(fd->stream.fd1, opts, PH_PASTOPEN, PH_LATE2)) < 0)
|
||||
return result;
|
||||
|
||||
applyopts_cloexec(fd->stream.fd, opts);
|
||||
applyopts_cloexec(fd->stream.fd1, opts);
|
||||
|
||||
applyopts_fchown(fd->stream.fd, opts);
|
||||
applyopts_fchown(fd->stream.fd1, opts);
|
||||
|
||||
if ((result = _xio_openlate(&fd->stream, opts)) < 0)
|
||||
return result;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/* $Id: xio-creat.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001 */
|
||||
/* $Id: xio-creat.h,v 1.4.2.1 2006/07/24 19:17:34 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_creat_h_included
|
||||
#define __xio_creat_h_included 1
|
||||
|
||||
extern const struct addrdesc addr_creat;
|
||||
extern const union xioaddr_desc *xioaddrs_creat[];
|
||||
|
||||
#endif /* !defined(__xio_creat_h_included) */
|
||||
|
|
27
xio-exec.c
27
xio-exec.c
|
@ -1,8 +1,11 @@
|
|||
/* $Id: xio-exec.c,v 1.19 2006/07/12 21:59:28 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* $Id: xio-exec.c,v 1.19.2.1 2006/07/24 19:17:35 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for opening addresses of exec type */
|
||||
/* this file contains the source for an inter address that just invokes a
|
||||
program. The program should provide its data side on FDs 0 and 1, and its
|
||||
protocol side on FDs 3 and 4. */
|
||||
|
||||
#include "xiosysincludes.h"
|
||||
#include "xioopen.h"
|
||||
|
@ -13,18 +16,25 @@
|
|||
|
||||
#if WITH_EXEC
|
||||
|
||||
static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
|
||||
static int xioopen_exec1end(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, /* XIO_RDONLY etc. */
|
||||
xiofile_t *fd,
|
||||
unsigned groups,
|
||||
int dummy1, int dummy2, int dummy3
|
||||
);
|
||||
|
||||
const struct addrdesc addr_exec = { "exec", 3, xioopen_exec, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, 0, 0, 0 HELP(":<command-line>") };
|
||||
|
||||
static const struct xioaddr_endpoint_desc xioaddr_exec1end = { XIOADDR_ENDPOINT, "exec", 1, XIOBIT_ALL, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_exec1end, 0, 0, 0 HELP(":<command-line>") };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_exec[] = {
|
||||
(union xioaddr_desc *)&xioaddr_exec1end,
|
||||
NULL };
|
||||
|
||||
|
||||
const struct optdesc opt_dash = { "dash", "login", OPT_DASH, GROUP_EXEC, PH_PREEXEC, TYPE_BOOL, OFUNC_SPEC };
|
||||
|
||||
static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
|
||||
|
||||
static int xioopen_exec1end(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, /* XIO_RDONLY, XIO_MAYCHILD etc. */
|
||||
xiofile_t *fd,
|
||||
unsigned groups,
|
||||
|
@ -39,7 +49,7 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
|
|||
|
||||
retropt_bool(opts, OPT_DASH, &dash);
|
||||
|
||||
status = _xioopen_foxec(xioflags, &fd->stream, groups, &opts);
|
||||
status = _xioopen_foxec_end(xioflags, &fd->stream, groups, &opts);
|
||||
if (status < 0) return status;
|
||||
if (status == 0) { /* child */
|
||||
const char *ends[] = { " ", NULL };
|
||||
|
@ -74,7 +84,7 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
|
|||
token = Malloc(len); /*! */
|
||||
tokp = token;
|
||||
if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
|
||||
true, true, false) < 0) {
|
||||
false, true, true, false) < 0) {
|
||||
Error("internal: miscalculated string lengths");
|
||||
}
|
||||
*tokp++ = '\0';
|
||||
|
@ -89,7 +99,7 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
|
|||
++strp;
|
||||
pargv[pargc++] = tokp;
|
||||
if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
|
||||
true, true, false) < 0) {
|
||||
false, true, true, false) < 0) {
|
||||
Error("internal: miscalculated string lengths");
|
||||
}
|
||||
*tokp++ = '\0';
|
||||
|
@ -134,4 +144,5 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
|
|||
/* parent */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* WITH_EXEC */
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/* $Id: xio-exec.h,v 1.6 2002/05/19 08:05:36 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001, 2002 */
|
||||
/* $Id: xio-exec.h,v 1.6.2.1 2006/07/24 19:17:37 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_exec_h_included
|
||||
#define __xio_exec_h_included 1
|
||||
|
||||
extern const struct addrdesc addr_exec;
|
||||
extern const union xioaddr_desc *xioaddrs_exec[];
|
||||
|
||||
extern const struct optdesc opt_dash;
|
||||
|
||||
|
|
5
xio-fd.c
5
xio-fd.c
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xio-fd.c,v 1.26 2006/12/28 07:35:50 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains common file descriptor related option definitions */
|
||||
|
@ -74,4 +74,5 @@ const struct optdesc opt_flock_ex_nb = { "flock-ex-nb", "flock-nb", OPT_FLOCK_E
|
|||
const struct optdesc opt_cool_write = { "cool-write", "coolwrite", OPT_COOL_WRITE, GROUP_FD, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.cool_write };
|
||||
|
||||
/* control closing of connections */
|
||||
const struct optdesc opt_end_close = { "end-close", "close", OPT_END_CLOSE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoend, END_CLOSE };
|
||||
const struct optdesc opt_end_close = { "end-close", NULL, OPT_END_CLOSE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoclose, XIOCLOSE_CLOSE };
|
||||
const struct optdesc opt_shut_none = { "shut-none", NULL, OPT_SHUT_NONE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoshut, XIOSHUT_NONE };
|
||||
|
|
3
xio-fd.h
3
xio-fd.h
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xio-fd.h,v 1.12 2006/12/28 07:35:50 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_fd_h_included
|
||||
|
@ -37,5 +37,6 @@ extern const struct optdesc opt_f_setlk_wr;
|
|||
extern const struct optdesc opt_f_setlkw_wr;
|
||||
extern const struct optdesc opt_cool_write;
|
||||
extern const struct optdesc opt_end_close;
|
||||
extern const struct optdesc opt_shut_none;
|
||||
|
||||
#endif /* !defined(__xio_fd_h_included) */
|
||||
|
|
72
xio-fdnum.c
72
xio-fdnum.c
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xio-fdnum.c,v 1.13 2006/07/08 10:03:14 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* $Id: xio-fdnum.c,v 1.13.2.1 2006/07/24 19:17:38 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for opening addresses of fdnum type */
|
||||
|
@ -15,8 +15,13 @@
|
|||
static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts, int rw, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
|
||||
|
||||
const struct addrdesc addr_fd = { "fd", 3, xioopen_fdnum, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 0, 0, 0 HELP(":<num>") };
|
||||
const struct xioaddr_endpoint_desc xioaddr_fdnum1 = { XIOADDR_ENDPOINT, "fd", 1, XIOBIT_ALL, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_fdnum, 0, 0, 0 HELP(":<num>") };
|
||||
const struct xioaddr_endpoint_desc xioaddr_fdnum2 = { XIOADDR_ENDPOINT, "fd", 2, XIOBIT_RDWR, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_fdnum, 0, 0, 0 HELP(":<numout>:<numin>") };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_fdnum[] = {
|
||||
(union xioaddr_desc *)&xioaddr_fdnum1,
|
||||
(union xioaddr_desc *)&xioaddr_fdnum2,
|
||||
NULL };
|
||||
|
||||
/* use some file descriptor and apply the options. Set the FD_CLOEXEC flag. */
|
||||
static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts,
|
||||
|
@ -24,23 +29,43 @@ static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts,
|
|||
int dummy1, int dummy2, int dummy3) {
|
||||
char *a1;
|
||||
int rw = (xioflags&XIO_ACCMODE);
|
||||
int numfd;
|
||||
int numfd1, numfd2 = -1;
|
||||
int result;
|
||||
|
||||
if (argc != 2) {
|
||||
Error3("%s:%s: wrong number of parameters (%d instead of 1)", argv[0], argv[1], argc-1);
|
||||
if (argc < 2 || argc > 3) {
|
||||
Error3("%s:%s: wrong number of parameters (%d instead of 1 or 2)", argv[0], argv[1], argc-1);
|
||||
}
|
||||
|
||||
numfd = strtoul(argv[1], &a1, 0);
|
||||
numfd1 = strtoul(argv[1], &a1, 0);
|
||||
if (*a1 != '\0') {
|
||||
Error1("error in FD number \"%s\"", argv[1]);
|
||||
}
|
||||
/* we dont want to see these fds in child processes */
|
||||
if (Fcntl_l(numfd, F_SETFD, FD_CLOEXEC) < 0) {
|
||||
Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", numfd, strerror(errno));
|
||||
if (Fcntl_l(numfd1, F_SETFD, FD_CLOEXEC) < 0) {
|
||||
Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", numfd1, strerror(errno));
|
||||
}
|
||||
Notice2("using file descriptor %d for %s", numfd, ddirection[rw]);
|
||||
if ((result = xioopen_fd(opts, rw, &xfd->stream, numfd, dummy2, dummy3)) < 0) {
|
||||
|
||||
if (argv[2]) {
|
||||
if (rw != XIO_RDWR) {
|
||||
Warn("two file descriptors given for unidirectional transfer");
|
||||
}
|
||||
numfd2 = numfd1;
|
||||
numfd1 = strtoul(argv[2], &a1, 0);
|
||||
if (*a1 != '\0') {
|
||||
Error1("error in FD number \"%s\"", argv[2]);
|
||||
}
|
||||
/* we dont want to see these fds in child processes */
|
||||
if (Fcntl_l(numfd2, F_SETFD, FD_CLOEXEC) < 0) {
|
||||
Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", numfd2, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (argv[2] == NULL) {
|
||||
Notice2("using file descriptor %d for %s", numfd1, ddirection[rw]);
|
||||
} else {
|
||||
Notice4("using file descriptors %d for %s and %d for %s", numfd1, ddirection[((rw+1)&1)-1], numfd2, ddirection[((rw+1)&2)-1]);
|
||||
}
|
||||
if ((result = xioopen_fd(opts, rw, xfd, numfd1, numfd2, dummy2, dummy3)) < 0) {
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
|
@ -52,27 +77,32 @@ static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts,
|
|||
|
||||
/* retrieve and apply options to a standard file descriptor.
|
||||
Do not set FD_CLOEXEC flag. */
|
||||
int xioopen_fd(struct opt *opts, int rw, xiosingle_t *xfd, int numfd, int dummy2, int dummy3) {
|
||||
int xioopen_fd(struct opt *opts, int rw, xiofile_t *xfd, int numfd1, int numfd2, int dummy2, int dummy3) {
|
||||
|
||||
xfd->fd = numfd;
|
||||
xfd->howtoend = END_NONE;
|
||||
xfd->stream.fd1 = numfd1;
|
||||
xfd->stream.fd2 = numfd2;
|
||||
if (numfd2 >= 0) {
|
||||
xfd->stream.fdtype = FDTYPE_DOUBLE;
|
||||
} else {
|
||||
xfd->stream.fdtype = FDTYPE_SINGLE;
|
||||
}
|
||||
|
||||
#if WITH_TERMIOS
|
||||
if (Isatty(xfd->fd)) {
|
||||
if (Tcgetattr(xfd->fd, &xfd->savetty) < 0) {
|
||||
if (Isatty(xfd->stream.fd1)) {
|
||||
if (Tcgetattr(xfd->stream.fd1, &xfd->stream.savetty) < 0) {
|
||||
Warn2("cannot query current terminal settings on fd %d: %s",
|
||||
xfd->fd, strerror(errno));
|
||||
xfd->stream.fd1, strerror(errno));
|
||||
} else {
|
||||
xfd->ttyvalid = true;
|
||||
xfd->stream.ttyvalid = true;
|
||||
}
|
||||
}
|
||||
#endif /* WITH_TERMIOS */
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
applyopts2(xfd->fd, opts, PH_INIT, PH_FD);
|
||||
applyopts2(xfd->stream.fd1, opts, PH_INIT, PH_FD);
|
||||
|
||||
return _xio_openlate(xfd, opts);
|
||||
return _xio_openlate(&xfd->stream, opts);
|
||||
}
|
||||
|
||||
#endif /* WITH_FD */
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
/* $Id: xio-fdnum.h,v 1.6 2006/03/21 20:48:31 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* $Id: xio-fdnum.h,v 1.6.2.1 2006/07/24 19:17:40 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_fdnum_h_included
|
||||
#define __xio_fdnum_h_included 1
|
||||
|
||||
extern const struct addrdesc addr_fd;
|
||||
extern const struct xioaddr_endpoint_desc xioaddr_fdnum1;
|
||||
extern const union xioaddr_desc *xioaddrs_fdnum[];
|
||||
|
||||
extern int xioopen_fd(struct opt *opts, int rw, xiosingle_t *xfd, int numfd, int dummy2, int dummy3);
|
||||
extern int xioopen_fd(struct opt *opts, int rw, xiofile_t *xfd, int numfd1, int numfd2, int dummy2, int dummy3);
|
||||
|
||||
#endif /* !defined(__xio_fdnum_h_included) */
|
||||
|
|
25
xio-file.c
25
xio-file.c
|
@ -11,7 +11,7 @@
|
|||
#include "xio-file.h"
|
||||
|
||||
|
||||
static int xioopen_open(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
static int xioopen_open1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
|
||||
|
||||
#if WITH_OPEN
|
||||
|
@ -66,13 +66,17 @@ const struct optdesc opt_o_trunc = { "o-trunc", "trunc", OPT_O_TRUNC,
|
|||
|
||||
#if _WITH_FILE /*! inconsistent name FILE vs. OPEN */
|
||||
|
||||
const struct addrdesc addr_open = { "open", 3, xioopen_open, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS, 0, 0, 0 HELP(":<filename>") };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_open1 = { XIOADDR_SYS, "open", 1, XIOBIT_ALL, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS, XIOSHUT_CLOSE, XIOCLOSE_CLOSE, xioopen_open1, 0, 0, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_open[] = {
|
||||
(union xioaddr_desc *)&xioaddr_open1,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* open for writing:
|
||||
if the filesystem entry already exists, the data is appended
|
||||
if it does not exist, a file is created and the data is appended
|
||||
*/
|
||||
static int xioopen_open(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) {
|
||||
static int xioopen_open1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) {
|
||||
const char *filename = argv[1];
|
||||
int rw = (xioflags & XIO_ACCMODE);
|
||||
bool exists;
|
||||
|
@ -96,13 +100,14 @@ static int xioopen_open(int argc, const char *argv[], struct opt *opts, int xiof
|
|||
filetypenames[(result&S_IFMT)>>12], filename, ddirection[rw]);
|
||||
if ((result = _xioopen_open(filename, rw, opts)) < 0)
|
||||
return result;
|
||||
fd->stream.fd = result;
|
||||
fd->stream.fd1 = result;
|
||||
fd->stream.fdtype = FDTYPE_SINGLE;
|
||||
|
||||
#if WITH_TERMIOS
|
||||
if (Isatty(fd->stream.fd)) {
|
||||
if (Tcgetattr(fd->stream.fd, &fd->stream.savetty) < 0) {
|
||||
if (Isatty(fd->stream.fd1)) {
|
||||
if (Tcgetattr(fd->stream.fd1, &fd->stream.savetty) < 0) {
|
||||
Warn2("cannot query current terminal settings on fd %d: %s",
|
||||
fd->stream.fd, strerror(errno));
|
||||
fd->stream.fd1, strerror(errno));
|
||||
} else {
|
||||
fd->stream.ttyvalid = true;
|
||||
}
|
||||
|
@ -110,10 +115,10 @@ static int xioopen_open(int argc, const char *argv[], struct opt *opts, int xiof
|
|||
#endif /* WITH_TERMIOS */
|
||||
|
||||
applyopts_named(filename, opts, PH_FD);
|
||||
applyopts(fd->stream.fd, opts, PH_FD);
|
||||
applyopts_cloexec(fd->stream.fd, opts);
|
||||
applyopts(fd->stream.fd1, opts, PH_FD);
|
||||
applyopts_cloexec(fd->stream.fd1, opts);
|
||||
|
||||
applyopts_fchown(fd->stream.fd, opts);
|
||||
applyopts_fchown(fd->stream.fd1, opts);
|
||||
|
||||
if ((result = _xio_openlate(&fd->stream, opts)) < 0)
|
||||
return result;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xio-file.h,v 1.8 2006/07/13 21:19:15 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* $Id: xio-file.h,v 1.8.2.1 2006/07/24 19:17:44 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_file_h_included
|
||||
|
@ -26,6 +26,6 @@ extern const struct optdesc opt_o_priv;
|
|||
extern const struct optdesc opt_o_trunc;
|
||||
extern const struct optdesc opt_o_noatime;
|
||||
|
||||
extern const struct addrdesc addr_open;
|
||||
extern const union xioaddr_desc *xioaddrs_open[];
|
||||
|
||||
#endif /* !defined(__xio_file_h_included) */
|
||||
|
|
92
xio-gopen.c
92
xio-gopen.c
|
@ -14,12 +14,17 @@
|
|||
|
||||
#if WITH_GOPEN
|
||||
|
||||
static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
static int xioopen_gopen1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
|
||||
|
||||
const struct addrdesc addr_gopen = { "gopen", 3, xioopen_gopen, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS|GROUP_SOCKET|GROUP_SOCK_UNIX, 0, 0, 0 HELP(":<filename>") };
|
||||
const struct xioaddr_endpoint_desc xioaddr_gopen1 = { XIOADDR_SYS, "gopen", 1, XIOBIT_ALL, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS|GROUP_SOCKET|GROUP_SOCK_UNIX, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_gopen1, 0, 0, 0 HELP(":<filename>") };
|
||||
|
||||
static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) {
|
||||
const union xioaddr_desc *xioaddrs_gopen[] = {
|
||||
(union xioaddr_desc *)&xioaddr_gopen1,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int xioopen_gopen1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) {
|
||||
const char *filename = argv[1];
|
||||
flags_t openflags = (xioflags & XIO_ACCMODE);
|
||||
mode_t st_mode;
|
||||
|
@ -76,24 +81,30 @@ static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xio
|
|||
/* save options, because we might have to start again with Socket() */
|
||||
opts2 = copyopts(opts, GROUP_ALL);
|
||||
|
||||
if ((fd->stream.fd = Socket(PF_UNIX, socktype, 0)) < 0) {
|
||||
if ((fd->stream.fd1 = Socket(PF_UNIX, socktype, 0)) < 0) {
|
||||
Error2("socket(PF_UNIX, %d, 0): %s", socktype, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
/*0 Info2("socket(PF_UNIX, %d, 0) -> %d", socktype, fd->stream.fd);*/
|
||||
applyopts(fd->stream.fd, opts, PH_PASTSOCKET);
|
||||
applyopts(fd->stream.fd, opts, PH_FD);
|
||||
fd->stream.fd2 = fd->stream.fd1;
|
||||
fd->stream.fdtype = FDTYPE_SINGLE;
|
||||
if (fd->stream.howtoshut == XIOSHUT_UNSPEC)
|
||||
fd->stream.howtoshut = XIOSHUT_DOWN;
|
||||
if (fd->stream.howtoclose == XIOCLOSE_UNSPEC)
|
||||
fd->stream.howtoclose = XIOCLOSE_CLOSE;
|
||||
/*0 Info2("socket(PF_UNIX, %d, 0) -> %d", socktype, fd->stream.fd1);*/
|
||||
applyopts(fd->stream.fd1, opts, PH_PASTSOCKET);
|
||||
applyopts(fd->stream.fd1, opts, PH_FD);
|
||||
|
||||
applyopts_cloexec(fd->stream.fd, opts);
|
||||
applyopts_cloexec(fd->stream.fd1, opts);
|
||||
|
||||
sa.sun_family = AF_UNIX;
|
||||
salen = xiosetunix(&sa, filename, false, false);
|
||||
|
||||
#if 0
|
||||
applyopts(fd->stream.fd, opts, PH_PREBIND);
|
||||
applyopts(fd->stream.fd, opts, PH_BIND);
|
||||
applyopts(fd->stream.fd1, opts, PH_PREBIND);
|
||||
applyopts(fd->stream.fd1, opts, PH_BIND);
|
||||
if (us) {
|
||||
if (Bind(fd->stream.fd, us, uslen) < 0) {
|
||||
if (Bind(fd->stream.fd1, us, uslen) < 0) {
|
||||
Error4("bind(%d, {%s}, "F_Zd"): %s",
|
||||
fd->fd, sockaddr_info(us, infobuff, sizeof(infobuff)),
|
||||
uslen, strerror(errno));
|
||||
|
@ -104,33 +115,33 @@ static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xio
|
|||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
applyopts(fd->stream.fd, opts, PH_PASTBIND);
|
||||
applyopts(fd->stream.fd1, opts, PH_PASTBIND);
|
||||
#endif /* 0 */
|
||||
|
||||
applyopts(fd->stream.fd, opts, PH_CONNECT);
|
||||
if ((result = Connect(fd->stream.fd, (struct sockaddr *)&sa, salen)) < 0) {
|
||||
applyopts(fd->stream.fd1, opts, PH_CONNECT);
|
||||
if ((result = Connect(fd->stream.fd1, (struct sockaddr *)&sa, salen)) < 0) {
|
||||
if (errno == EINPROGRESS) {
|
||||
Warn4("connect(%d, %s, "F_Zd"): %s",
|
||||
fd->stream.fd, sockaddr_unix_info(&sa, salen, infobuff, sizeof(infobuff)),
|
||||
fd->stream.fd1, sockaddr_unix_info(&sa, salen, infobuff, sizeof(infobuff)),
|
||||
sizeof(sa), strerror(errno));
|
||||
} else if (errno == EPROTOTYPE && optsotype != SOCK_STREAM) {
|
||||
Warn4("connect(%d, %s, "F_Zd"): %s",
|
||||
fd->stream.fd, sockaddr_unix_info(&sa, salen, infobuff, sizeof(infobuff)),
|
||||
fd->stream.fd1, sockaddr_unix_info(&sa, salen, infobuff, sizeof(infobuff)),
|
||||
sizeof(sa), strerror(errno));
|
||||
Info("assuming datagram socket");
|
||||
Close(fd->stream.fd);
|
||||
Close(fd->stream.fd1);
|
||||
|
||||
opts = opts2;
|
||||
if ((fd->stream.fd = Socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
|
||||
if ((fd->stream.fd1 = Socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
|
||||
Error1("socket(PF_UNIX, SOCK_DGRAM, 0): %s", strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
/*0 Info1("socket(PF_UNIX, SOCK_DGRAM, 0) -> %d", fd->stream.fd);*/
|
||||
/*0 Info1("socket(PF_UNIX, SOCK_DGRAM, 0) -> %d", fd->stream.fd1);*/
|
||||
|
||||
applyopts(fd->stream.fd, opts, PH_PASTSOCKET);
|
||||
applyopts(fd->stream.fd, opts, PH_FD);
|
||||
applyopts(fd->stream.fd1, opts, PH_PASTSOCKET);
|
||||
applyopts(fd->stream.fd1, opts, PH_FD);
|
||||
|
||||
applyopts_cloexec(fd->stream.fd, opts);
|
||||
applyopts_cloexec(fd->stream.fd1, opts);
|
||||
|
||||
sa.sun_family = AF_UNIX;
|
||||
strncpy(sa.sun_path, filename, sizeof(sa.sun_path));
|
||||
|
@ -140,23 +151,24 @@ static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xio
|
|||
memcpy(&fd->stream.peersa.soa, &sa, fd->stream.salen);
|
||||
} else {
|
||||
Error4("connect(%d, %s, "F_Zd"): %s",
|
||||
fd->stream.fd, sockaddr_unix_info(&sa, fd->stream.salen, infobuff, sizeof(infobuff)),
|
||||
fd->stream.fd1, sockaddr_unix_info(&sa, fd->stream.salen, infobuff, sizeof(infobuff)),
|
||||
sizeof(sa), strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
if (fd->stream.howtoend == END_UNSPEC) {
|
||||
fd->stream.howtoend = END_SHUTDOWN;
|
||||
}
|
||||
if (fd->stream.howtoshut == XIOSHUT_UNSPEC)
|
||||
fd->stream.howtoshut = XIOSHUT_CLOSE;
|
||||
if (fd->stream.howtoclose == XIOCLOSE_UNSPEC)
|
||||
fd->stream.howtoclose = XIOCLOSE_CLOSE;
|
||||
|
||||
applyopts_fchown(fd->stream.fd, opts);
|
||||
applyopts(fd->stream.fd, opts, PH_CONNECTED);
|
||||
applyopts(fd->stream.fd, opts, PH_LATE);
|
||||
applyopts_fchown(fd->stream.fd1, opts);
|
||||
applyopts(fd->stream.fd1, opts, PH_CONNECTED);
|
||||
applyopts(fd->stream.fd1, opts, PH_LATE);
|
||||
applyopts_named(filename, opts, PH_PASTOPEN); /* unlink-late */
|
||||
|
||||
if (Getsockname(fd->stream.fd, (struct sockaddr *)&us, &uslen) < 0) {
|
||||
if (Getsockname(fd->stream.fd1, (struct sockaddr *)&us, &uslen) < 0) {
|
||||
Warn4("getsockname(%d, %p, {%d}): %s",
|
||||
fd->stream.fd, &us, uslen, strerror(errno));
|
||||
fd->stream.fd1, &us, uslen, strerror(errno));
|
||||
} else {
|
||||
Notice1("successfully connected via %s",
|
||||
sockaddr_unix_info(&us, uslen, infobuff, sizeof(infobuff)));
|
||||
|
@ -190,24 +202,28 @@ static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xio
|
|||
Ioctl(result, I_PUSH, "ttcompat");
|
||||
}
|
||||
#endif
|
||||
fd->stream.fd = result;
|
||||
if (fd->stream.howtoshut == XIOSHUT_UNSPEC)
|
||||
fd->stream.howtoshut = XIOSHUT_NONE;
|
||||
if (fd->stream.howtoclose == XIOCLOSE_UNSPEC)
|
||||
fd->stream.howtoclose = XIOCLOSE_CLOSE;
|
||||
fd->stream.fd1 = result;
|
||||
|
||||
#if WITH_TERMIOS
|
||||
if (Isatty(fd->stream.fd)) {
|
||||
if (Tcgetattr(fd->stream.fd, &fd->stream.savetty) < 0) {
|
||||
if (Isatty(fd->stream.fd1)) {
|
||||
if (Tcgetattr(fd->stream.fd1, &fd->stream.savetty) < 0) {
|
||||
Warn2("cannot query current terminal settings on fd %d: %s",
|
||||
fd->stream.fd, strerror(errno));
|
||||
fd->stream.fd1, strerror(errno));
|
||||
} else {
|
||||
fd->stream.ttyvalid = true;
|
||||
}
|
||||
}
|
||||
#endif /* WITH_TERMIOS */
|
||||
applyopts_named(filename, opts, PH_FD);
|
||||
applyopts(fd->stream.fd, opts, PH_FD);
|
||||
applyopts_cloexec(fd->stream.fd, opts);
|
||||
applyopts(fd->stream.fd1, opts, PH_FD);
|
||||
applyopts_cloexec(fd->stream.fd1, opts);
|
||||
}
|
||||
|
||||
if ((result = applyopts2(fd->stream.fd, opts, PH_PASTSOCKET, PH_CONNECTED)) < 0)
|
||||
if ((result = applyopts2(fd->stream.fd1, opts, PH_PASTSOCKET, PH_CONNECTED)) < 0)
|
||||
return result;
|
||||
|
||||
if ((result = _xio_openlate(&fd->stream, opts)) < 0)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
/* $Id: xio-gopen.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001 */
|
||||
/* $Id: xio-gopen.h,v 1.4.2.1 2006/07/24 19:17:49 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_gopen_h_included
|
||||
#define __xio_gopen_h_included 1
|
||||
|
||||
extern const struct addrdesc addr_gopen;
|
||||
extern const struct xioaddr_endpoint_desc xioaddr_gopen1;
|
||||
extern const union xioaddr_desc *xioaddrs_gopen[];
|
||||
|
||||
#endif /* !defined(__xio_gopen_h_included) */
|
||||
|
|
19
xio-ipapp.c
19
xio-ipapp.c
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "xiosysincludes.h"
|
||||
|
||||
#if WITH_TCP || WITH_UDP
|
||||
#if _WITH_TCP || _WITH_UDP
|
||||
|
||||
#include "xioopen.h"
|
||||
#include "xio-socket.h"
|
||||
|
@ -19,7 +19,7 @@ const struct optdesc opt_sourceport = { "sourceport", "sp", OPT_SOURCEPORT
|
|||
/*const struct optdesc opt_port = { "port", NULL, OPT_PORT, GROUP_IPAPP, PH_BIND, TYPE_USHORT, OFUNC_SPEC };*/
|
||||
const struct optdesc opt_lowport = { "lowport", NULL, OPT_LOWPORT, GROUP_IPAPP, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
|
||||
|
||||
#if WITH_IP4
|
||||
#if _WITH_IP4
|
||||
/* we expect the form "host:port" */
|
||||
int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
|
@ -42,8 +42,6 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
|||
Error2("%s: wrong number of parameters (%d instead of 2)", argv[0], argc-1);
|
||||
}
|
||||
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
|
@ -124,7 +122,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
|||
}
|
||||
/* parent process */
|
||||
Notice1("forked off child process "F_pid, pid);
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
/* with and without retry */
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
|
@ -214,10 +212,10 @@ int
|
|||
sockaddr_info((struct sockaddr *)them, *themlen, infobuff, sizeof(infobuff)));
|
||||
return STAT_OK;
|
||||
}
|
||||
#endif /* WITH_IP4 */
|
||||
#endif /* _WITH_IP4 */
|
||||
|
||||
|
||||
#if WITH_TCP && WITH_LISTEN
|
||||
#if _WITH_TCP && WITH_LISTEN
|
||||
int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0,
|
||||
const char *portname, int *pf, int ipproto,
|
||||
unsigned long res_opts0,
|
||||
|
@ -271,7 +269,8 @@ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts,
|
|||
#endif
|
||||
}
|
||||
|
||||
fd->stream.howtoend = END_SHUTDOWN;
|
||||
fd->stream.howtoshut = XIOSHUT_DOWN;
|
||||
fd->stream.howtoclose = XIOCLOSE_CLOSE;
|
||||
|
||||
if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
@ -293,6 +292,6 @@ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts,
|
|||
return result;
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_IP4 && WITH_TCP && WITH_LISTEN */
|
||||
#endif /* _WITH_IP4 && _WITH_TCP && WITH_LISTEN */
|
||||
|
||||
#endif /* WITH_TCP || WITH_UDP */
|
||||
#endif /* _WITH_TCP || _WITH_UDP */
|
||||
|
|
78
xio-listen.c
78
xio-listen.c
|
@ -115,46 +115,24 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
|
|||
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
|
||||
#if 1
|
||||
if (dofork) {
|
||||
#if HAVE_SIGACTION
|
||||
struct sigaction act;
|
||||
memset(&act, 0, sizeof(struct sigaction));
|
||||
act.sa_flags = SA_NOCLDSTOP|SA_RESTART
|
||||
#ifdef SA_NOMASK
|
||||
|SA_NOMASK
|
||||
#endif
|
||||
;
|
||||
act.sa_handler = childdied;
|
||||
if (Sigaction(SIGCHLD, &act, NULL) < 0) {
|
||||
/*! man does not say that errno is defined */
|
||||
Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied, strerror(errno));
|
||||
}
|
||||
#else /* HAVE_SIGACTION */
|
||||
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
|
||||
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
|
||||
}
|
||||
#endif /* !HAVE_SIGACTION */
|
||||
}
|
||||
#endif /* 1 */
|
||||
|
||||
if ((xfd->fd = Socket(pf, socktype, proto)) < 0) {
|
||||
if ((xfd->fd1 = Socket(pf, socktype, proto)) < 0) {
|
||||
Msg4(level,
|
||||
"socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
xfd->fdtype = FDTYPE_SINGLE;
|
||||
|
||||
applyopts(xfd->fd, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->fd1, opts, PH_PASTSOCKET);
|
||||
|
||||
applyopts_cloexec(xfd->fd, opts);
|
||||
applyopts_cloexec(xfd->fd1, opts);
|
||||
|
||||
applyopts(xfd->fd, opts, PH_PREBIND);
|
||||
applyopts(xfd->fd, opts, PH_BIND);
|
||||
if (Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd,
|
||||
applyopts(xfd->fd1, opts, PH_PREBIND);
|
||||
applyopts(xfd->fd1, opts, PH_BIND);
|
||||
if (Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1,
|
||||
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
|
||||
strerror(errno));
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
|
@ -166,12 +144,12 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
|
|||
/* under some circumstances (e.g., TCP listen on port 0) bind() fills empty
|
||||
fields that we want to know. */
|
||||
salen = sizeof(sa);
|
||||
if (Getsockname(xfd->fd, us, &uslen) < 0) {
|
||||
if (Getsockname(xfd->fd1, us, &uslen) < 0) {
|
||||
Warn4("getsockname(%d, %p, {%d}): %s",
|
||||
xfd->fd, &us, uslen, strerror(errno));
|
||||
xfd->fd1, &us, uslen, strerror(errno));
|
||||
}
|
||||
|
||||
applyopts(xfd->fd, opts, PH_PASTBIND);
|
||||
applyopts(xfd->fd1, opts, PH_PASTBIND);
|
||||
#if WITH_UNIX
|
||||
if (us->sa_family == AF_UNIX) {
|
||||
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
|
||||
|
@ -181,8 +159,8 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
|
|||
#endif /* WITH_UNIX */
|
||||
|
||||
retropt_int(opts, OPT_BACKLOG, &backlog);
|
||||
if (Listen(xfd->fd, backlog) < 0) {
|
||||
Error3("listen(%d, %d): %s", xfd->fd, backlog, strerror(errno));
|
||||
if (Listen(xfd->fd1, backlog) < 0) {
|
||||
Error3("listen(%d, %d): %s", xfd->fd1, backlog, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
|
@ -229,9 +207,9 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
|
|||
do {
|
||||
/*? int level = E_ERROR;*/
|
||||
Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname)));
|
||||
ps = Accept(xfd->fd, (struct sockaddr *)&sa, &salen);
|
||||
ps = Accept(xfd->fd1, (struct sockaddr *)&sa, &salen);
|
||||
if (ps >= 0) {
|
||||
/*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", xfd->fd, &sa, salen, ps);*/
|
||||
/*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", xfd->fd1, &sa, salen, ps);*/
|
||||
break; /* success, break out of loop */
|
||||
}
|
||||
if (errno == EINTR) {
|
||||
|
@ -239,12 +217,12 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
|
|||
}
|
||||
if (errno == ECONNABORTED) {
|
||||
Notice4("accept(%d, %p, {"F_Zu"}): %s",
|
||||
xfd->fd, &sa, salen, strerror(errno));
|
||||
xfd->fd1, &sa, salen, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
Msg4(level, "accept(%d, %p, {"F_Zu"}): %s",
|
||||
xfd->fd, &sa, salen, strerror(errno));
|
||||
Close(xfd->fd);
|
||||
xfd->fd1, &sa, salen, strerror(errno));
|
||||
Close(xfd->fd1);
|
||||
return STAT_RETRYLATER;
|
||||
} while (true);
|
||||
applyopts_cloexec(ps, opts);
|
||||
|
@ -271,21 +249,21 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
|
|||
sockaddr_info((struct sockaddr *)pa, pas,
|
||||
infobuff, sizeof(infobuff)));
|
||||
|
||||
applyopts(xfd->fd, opts, PH_FD);
|
||||
applyopts(xfd->fd1, opts, PH_FD);
|
||||
|
||||
applyopts(xfd->fd, opts, PH_CONNECTED);
|
||||
applyopts(xfd->fd1, opts, PH_CONNECTED);
|
||||
|
||||
if (dofork) {
|
||||
if ((pid = Fork()) < 0) {
|
||||
Msg1(level, "fork(): %s", strerror(errno));
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
if (pid == 0) { /* child */
|
||||
if (Close(xfd->fd) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd, strerror(errno));
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
}
|
||||
xfd->fd = ps;
|
||||
xfd->fd1 = ps;
|
||||
|
||||
#if WITH_RETRY
|
||||
/* !? */
|
||||
|
@ -317,10 +295,10 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
|
|||
Notice1("forked off child process "F_pid, pid);
|
||||
Info("still listening");
|
||||
} else {
|
||||
if (Close(xfd->fd) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd, strerror(errno));
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
}
|
||||
xfd->fd = ps;
|
||||
xfd->fd1 = ps;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
64
xio-nop.c
Normal file
64
xio-nop.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
/* $Id: xio-socks.c,v 1.25 2006/02/08 19:46:59 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2006-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for a degenerated address that just transfers
|
||||
data */
|
||||
|
||||
#include "xiosysincludes.h"
|
||||
#include "xioopen.h"
|
||||
|
||||
#include "xio-nop.h"
|
||||
|
||||
|
||||
#if WITH_NOP
|
||||
|
||||
static int xioopen_nop(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups, int dummy1, int dummy2,
|
||||
int dummy3);
|
||||
|
||||
static const struct xioaddr_inter_desc xiointer_nop0ro = { XIOADDR_PROT, "nop", 0, XIOBIT_RDONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_nop, 0, 0, 0, XIOBIT_WRONLY HELP("") };
|
||||
static const struct xioaddr_inter_desc xiointer_nop0wo = { XIOADDR_PROT, "nop", 0, XIOBIT_WRONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_nop, 0, 0, 0, XIOBIT_RDONLY HELP("") };
|
||||
static const struct xioaddr_inter_desc xiointer_nop0rw = { XIOADDR_PROT, "nop", 0, XIOBIT_RDWR, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_nop, 0, 0, 0, XIOBIT_RDWR HELP("") };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_nop[] = {
|
||||
(union xioaddr_desc *)&xiointer_nop0ro,
|
||||
(union xioaddr_desc *)&xiointer_nop0wo,
|
||||
(union xioaddr_desc *)&xiointer_nop0rw,
|
||||
NULL };
|
||||
|
||||
static int xioopen_nop(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups, int dummy, int dummy2,
|
||||
int dummy3) {
|
||||
struct single *xfd = &xxfd->stream;
|
||||
int result;
|
||||
|
||||
if (argc != 1) {
|
||||
Error("address NOP takes no arguments");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
if (xfd->fd1 < 0 && xfd->fd2 < 0) {
|
||||
Error("NOP cannot be endpoint");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
|
||||
Notice("opening NOP");
|
||||
|
||||
xfd->dtype = XIODATA_STREAM;
|
||||
/*xfd->fdtype = FDTYPE_DOUBLE;*/
|
||||
|
||||
applyopts(xfd->fd1, opts, PH_ALL);
|
||||
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
return result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_NOP */
|
||||
|
10
xio-nop.h
Normal file
10
xio-nop.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
/* $Id: xio-socks.h,v 1.6 2004/06/06 19:03:28 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2006-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_nop_h_included
|
||||
#define __xio_nop_h_included 1
|
||||
|
||||
extern const union xioaddr_desc *xioaddrs_nop[];
|
||||
|
||||
#endif /* !defined(__xio_nop_h_included) */
|
251
xio-openssl.c
251
xio-openssl.c
|
@ -51,15 +51,44 @@ static int xioSSL_set_fd(struct single *xfd, int level);
|
|||
static int xioSSL_connect(struct single *xfd, bool opt_ver, int level);
|
||||
|
||||
|
||||
/* description record for ssl connect */
|
||||
const struct addrdesc addr_openssl = {
|
||||
"openssl", /* keyword for selecting this address type in xioopen calls
|
||||
/* description record for inter-address ssl connect with 0 parameters */
|
||||
static const struct xioaddr_inter_desc xiointer_openssl_connect0 = {
|
||||
XIOADDR_INTER, /* this is an embedded address (inter module) */
|
||||
"openssl-client", /* keyword for selecting this address type in xioopen calls
|
||||
(canonical or main name) */
|
||||
3, /* data flow directions this address supports on API layer:
|
||||
1..read, 2..write, 3..both */
|
||||
0, /* number of required parameters */
|
||||
XIOBIT_ALL, /* data flow directions this address supports on API layer:
|
||||
XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR */
|
||||
GROUP_CHILD|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to.
|
||||
You might have to specify a new group in xioopts.h */
|
||||
XIOSHUT_OPENSSL,
|
||||
XIOCLOSE_CLOSE,
|
||||
xioopen_openssl_connect, /* a function pointer used to "open" these addresses.*/
|
||||
0, /* an integer passed to xioopen_openssl; makes it possible to
|
||||
use the same xioopen_openssl function for slightly different
|
||||
address types. */
|
||||
0, /* like previous argument */
|
||||
0, /* like previous arguments, but pointer type.
|
||||
No trailing comma or semicolon! */
|
||||
XIOBIT_RDWR /* SSL is a bidirectional protocol */
|
||||
HELP("") /* a text displayed from xio help function.
|
||||
No trailing comma or semicolon!
|
||||
only generates this text if WITH_HELP is != 0 */
|
||||
} ;
|
||||
|
||||
/* description record for endpoint-address ssl connect with 2 parameters */
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_openssl_connect2 = {
|
||||
XIOADDR_ENDPOINT, /* this is not an embedded address but a sys address */
|
||||
"openssl-client", /* keyword for selecting this address type in xioopen calls
|
||||
(canonical or main name) */
|
||||
2, /* number of required parameters */
|
||||
XIOBIT_ALL, /* data flow directions this address supports on API layer:
|
||||
XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR */
|
||||
GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to.
|
||||
You might have to specify a new group in xioopts.h */
|
||||
XIOSHUT_OPENSSL,
|
||||
XIOCLOSE_CLOSE,
|
||||
xioopen_openssl_connect, /* a function pointer used to "open" these addresses.*/
|
||||
0, /* an integer passed to xioopen_openssl; makes it possible to
|
||||
use the same xioopen_openssl function for slightly different
|
||||
address types. */
|
||||
|
@ -71,16 +100,53 @@ const struct addrdesc addr_openssl = {
|
|||
only generates this text if WITH_HELP is != 0 */
|
||||
} ;
|
||||
|
||||
/* array containing ssl connect description records */
|
||||
const union xioaddr_desc *xioaddrs_openssl_connect[] = {
|
||||
(union xioaddr_desc *)&xiointer_openssl_connect0,
|
||||
(union xioaddr_desc *)&xioendpoint_openssl_connect2,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
#if WITH_LISTEN
|
||||
/* description record for ssl listen */
|
||||
const struct addrdesc addr_openssl_listen = {
|
||||
"openssl-listen", /* keyword for selecting this address type in xioopen calls
|
||||
/* description record for inter-address ssl listen */
|
||||
static const struct xioaddr_inter_desc xiointer_openssl_listen0 = {
|
||||
XIOADDR_INTER, /* this is an embedded address (inter module) */
|
||||
"openssl-server", /* keyword for selecting this address type in xioopen calls
|
||||
(canonical or main name) */
|
||||
3, /* data flow directions this address supports on API layer:
|
||||
1..read, 2..write, 3..both */
|
||||
0, /* number of required parameters */
|
||||
XIOBIT_ALL, /* data flow directions this address supports on API layer:
|
||||
XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR */
|
||||
GROUP_CHILD|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to.
|
||||
You might have to specify a new group in xioopts.h */
|
||||
XIOSHUT_OPENSSL,
|
||||
XIOCLOSE_CLOSE,
|
||||
xioopen_openssl_listen, /* a function pointer used to "open" these addresses.*/
|
||||
0, /* an integer passed to xioopen_openssl_listen; makes it possible to
|
||||
use the same xioopen_openssl_listen function for slightly different
|
||||
address types. */
|
||||
0, /* like previous argument */
|
||||
0, /* like previous arguments, but pointer type.
|
||||
No trailing comma or semicolon! */
|
||||
XIOBIT_RDWR /* SSL is a bidirectional protocol */
|
||||
HELP("") /* a text displayed from xio help function.
|
||||
No trailing comma or semicolon!
|
||||
only generates this text if WITH_HELP is != 0 */
|
||||
} ;
|
||||
|
||||
/* description record for enpoint-address ssl listen */
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_openssl_listen1 = {
|
||||
XIOADDR_ENDPOINT, /* this is not an embedded module but a sys module */
|
||||
"openssl-server", /* keyword for selecting this address type in xioopen calls
|
||||
(canonical or main name) */
|
||||
1, /* number of required parameters */
|
||||
XIOBIT_ALL, /* data flow directions this address supports on API layer:
|
||||
XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR */
|
||||
GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to.
|
||||
You might have to specify a new group in xioopts.h */
|
||||
XIOSHUT_OPENSSL,
|
||||
XIOCLOSE_CLOSE,
|
||||
xioopen_openssl_listen, /* a function pointer used to "open" these addresses.*/
|
||||
0, /* an integer passed to xioopen_openssl_listen; makes it possible to
|
||||
use the same xioopen_openssl_listen function for slightly different
|
||||
address types. */
|
||||
|
@ -91,6 +157,13 @@ const struct addrdesc addr_openssl_listen = {
|
|||
No trailing comma or semicolon!
|
||||
only generates this text if WITH_HELP is != 0 */
|
||||
} ;
|
||||
|
||||
/* array containing ssl listen description records */
|
||||
const union xioaddr_desc *xioaddrs_openssl_listen[] = {
|
||||
(union xioaddr_desc *)&xiointer_openssl_listen0,
|
||||
(union xioaddr_desc *)&xioendpoint_openssl_listen1,
|
||||
NULL
|
||||
};
|
||||
#endif /* WITH_LISTEN */
|
||||
|
||||
/* both client and server */
|
||||
|
@ -153,7 +226,7 @@ static int
|
|||
{
|
||||
struct single *xfd = &xxfd->stream;
|
||||
struct opt *opts0 = NULL;
|
||||
const char *hostname, *portname;
|
||||
const char *hostname, *portname = NULL;
|
||||
int pf = PF_UNSPEC;
|
||||
int ipproto = IPPROTO_TCP;
|
||||
int socktype = SOCK_STREAM;
|
||||
|
@ -165,7 +238,7 @@ static int
|
|||
bool needbind = false;
|
||||
bool lowport = false;
|
||||
int level;
|
||||
SSL_CTX* ctx;
|
||||
/*0 SSL_CTX* ctx;*/
|
||||
bool opt_ver = true; /* verify peer certificate */
|
||||
char *opt_cert = NULL; /* file name of client certificate */
|
||||
int result;
|
||||
|
@ -176,15 +249,18 @@ static int
|
|||
}
|
||||
xfd->flags |= XIO_DOESCONVERT;
|
||||
|
||||
if (argc != 3) {
|
||||
Error1("%s: 2 parameters required", argv[0]);
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
xfd->howtoshut = XIOSHUT_OPENSSL;
|
||||
xfd->howtoclose = XIOCLOSE_CLOSE;
|
||||
|
||||
/* we support two forms of openssl-connect */
|
||||
if (argc == 3) {
|
||||
hostname = argv[1];
|
||||
portname = argv[2];
|
||||
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
/* a "terminal" form where we build a tcp connection to given host and
|
||||
port */
|
||||
|
||||
applyopts_single(xfd, opts, PH_INIT);
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
retropt_bool(opts, OPT_FORK, &dofork);
|
||||
|
@ -192,7 +268,8 @@ static int
|
|||
retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
|
||||
|
||||
result =
|
||||
_xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert, &ctx);
|
||||
_xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert,
|
||||
&xfd->para.openssl.ctx);
|
||||
if (result != STAT_OK) return STAT_NORETRY;
|
||||
|
||||
result =
|
||||
|
@ -202,6 +279,32 @@ static int
|
|||
them, &themlen, us, &uslen,
|
||||
&needbind, &lowport, &socktype);
|
||||
if (result != STAT_OK) return STAT_NORETRY;
|
||||
} else if (argc = 1) {
|
||||
|
||||
/* or a "non terminal" address without required parameters */
|
||||
if (xfd->fd2 < 0) {
|
||||
Error("openssl-connect without hostname and port must be an embedded address");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
retropt_bool(opts, OPT_FORK, &dofork);
|
||||
|
||||
retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
|
||||
|
||||
result =
|
||||
_xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert,
|
||||
&xfd->para.openssl.ctx);
|
||||
if (result != STAT_OK) return STAT_NORETRY;
|
||||
|
||||
retropt_bool(opts, OPT_FORK, &dofork);
|
||||
|
||||
} else {
|
||||
Error1("%s: 0 or 2 parameters required", argv[0]);
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
if (xioopts.logopt == 'm') {
|
||||
Info("starting connect loop, switching to syslog");
|
||||
|
@ -219,6 +322,8 @@ static int
|
|||
#endif /* WITH_RETRY */
|
||||
level = E_ERROR;
|
||||
|
||||
/*!!! this belongs only to "old" openssl-connect form */
|
||||
if (portname) {
|
||||
/* this cannot fork because we retrieved fork option above */
|
||||
result =
|
||||
_xioopen_connect(xfd,
|
||||
|
@ -243,20 +348,24 @@ static int
|
|||
default:
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/*! isn't this too early? */
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = _xioopen_openssl_connect(xfd, opt_ver, ctx, level);
|
||||
result =
|
||||
_xioopen_openssl_connect(xfd, opt_ver, xfd->para.openssl.ctx, level);
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
#if WITH_RETRY
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (xfd->forever || xfd->retry) {
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
if (xfd->fdtype == FDTYPE_DOUBLE)
|
||||
Close(xfd->fd2);
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
if (result == STAT_RETRYLATER) {
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
|
@ -297,7 +406,9 @@ static int
|
|||
}
|
||||
/* parent process */
|
||||
Notice1("forked off child process "F_pid, pid);
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
if (xfd->fdtype == FDTYPE_DOUBLE)
|
||||
Close(xfd->fd2);
|
||||
sycSSL_free(xfd->para.openssl.ssl);
|
||||
xfd->para.openssl.ssl = NULL;
|
||||
/* with and without retry */
|
||||
|
@ -383,7 +494,7 @@ static int
|
|||
addr_openssl */
|
||||
{
|
||||
struct single *xfd = &xxfd->stream;
|
||||
const char *portname;
|
||||
const char *portname = NULL;
|
||||
struct opt *opts0 = NULL;
|
||||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
|
@ -392,7 +503,7 @@ static int
|
|||
int ipproto = IPPROTO_TCP;
|
||||
/*! lowport? */
|
||||
int level;
|
||||
SSL_CTX* ctx;
|
||||
/*0 SSL_CTX* ctx;*/
|
||||
bool opt_ver = true; /* verify peer certificate - changed with 1.6.0 */
|
||||
char *opt_cert = NULL; /* file name of server certificate */
|
||||
int result;
|
||||
|
@ -403,11 +514,6 @@ static int
|
|||
}
|
||||
xfd->flags |= XIO_DOESCONVERT;
|
||||
|
||||
if (argc != 2) {
|
||||
Error1("%s: 1 parameter required", argv[0]);
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
#if WITH_IP4 && WITH_IP6
|
||||
pf = xioopts.default_ip=='6'?PF_INET6:PF_INET;
|
||||
#elif WITH_IP6
|
||||
|
@ -416,9 +522,36 @@ static int
|
|||
pf = PF_INET;
|
||||
#endif
|
||||
|
||||
portname = argv[1];
|
||||
if (argc == 2) {
|
||||
|
||||
portname = argv[1];
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
|
||||
if (opt_cert == NULL) {
|
||||
Warn("no certificate given; consider option \"cert\"");
|
||||
}
|
||||
|
||||
result =
|
||||
_xioopen_openssl_prepare(opts, xfd, true, &opt_ver, opt_cert,
|
||||
&xfd->para.openssl.ctx);
|
||||
if (result != STAT_OK) return STAT_NORETRY;
|
||||
|
||||
if (_xioopen_ipapp_listen_prepare(opts, &opts0, portname, &pf, ipproto,
|
||||
xfd->para.socket.ip.res_opts[1],
|
||||
xfd->para.socket.ip.res_opts[0],
|
||||
us, &uslen, &socktype)
|
||||
!= STAT_OK) {
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
} else if (argc == 1) {
|
||||
if (xfd->fd1 < 0) {
|
||||
Error("openssl-listen without port must be an embedded address");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
|
@ -430,18 +563,15 @@ static int
|
|||
applyopts(-1, opts, PH_EARLY);
|
||||
|
||||
result =
|
||||
_xioopen_openssl_prepare(opts, xfd, true, &opt_ver, opt_cert, &ctx);
|
||||
_xioopen_openssl_prepare(opts, xfd, true, &opt_ver, opt_cert,
|
||||
&xfd->para.openssl.ctx);
|
||||
if (result != STAT_OK) return STAT_NORETRY;
|
||||
|
||||
if (_xioopen_ipapp_listen_prepare(opts, &opts0, portname, &pf, ipproto,
|
||||
xfd->para.socket.ip.res_opts[1],
|
||||
xfd->para.socket.ip.res_opts[0],
|
||||
us, &uslen, &socktype)
|
||||
!= STAT_OK) {
|
||||
return STAT_NORETRY;
|
||||
} else {
|
||||
Error1("%s: 1 parameter required", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xfd->addr = &addr_openssl_listen;
|
||||
xfd->dtype = XIODATA_OPENSSL;
|
||||
|
||||
while (true) { /* loop over failed attempts */
|
||||
|
@ -453,6 +583,7 @@ static int
|
|||
#endif /* WITH_RETRY */
|
||||
level = E_ERROR;
|
||||
|
||||
if (portname) {
|
||||
/* tcp listen; this can fork() for us; it only returns on error or on
|
||||
successful establishment of tcp connection */
|
||||
result = _xioopen_listen(xfd, xioflags,
|
||||
|
@ -464,6 +595,7 @@ static int
|
|||
E_ERROR
|
||||
#endif /* WITH_RETRY */
|
||||
);
|
||||
}
|
||||
/*! not sure if we should try again on retry/forever */
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
|
@ -484,8 +616,8 @@ static int
|
|||
default:
|
||||
return result;
|
||||
}
|
||||
|
||||
result = _xioopen_openssl_listen(xfd, opt_ver, ctx, level);
|
||||
result =
|
||||
_xioopen_openssl_listen(xfd, opt_ver, xfd->para.openssl.ctx, level);
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
#if WITH_RETRY
|
||||
|
@ -537,12 +669,11 @@ int _xioopen_openssl_listen(struct single *xfd,
|
|||
}
|
||||
|
||||
/* assign the network connection to the SSL object */
|
||||
if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->fd) <= 0) {
|
||||
if (ERR_peek_error() == 0) Msg(level, "SSL_set_fd() failed");
|
||||
while (err = ERR_get_error()) {
|
||||
Msg2(level, "SSL_set_fd(, %d): %s",
|
||||
xfd->fd, ERR_error_string(err, NULL));
|
||||
}
|
||||
ret = xioSSL_set_fd(xfd, level);
|
||||
if (ret != STAT_OK) {
|
||||
sycSSL_free(xfd->para.openssl.ssl);
|
||||
xfd->para.openssl.ssl = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if WITH_DEBUG
|
||||
|
@ -634,7 +765,6 @@ int
|
|||
unsigned long err;
|
||||
int result;
|
||||
|
||||
xfd->addr = &addr_openssl;
|
||||
xfd->dtype = XIODATA_OPENSSL;
|
||||
|
||||
retropt_bool(opts, OPT_OPENSSL_FIPS, &opt_fips);
|
||||
|
@ -751,7 +881,7 @@ int
|
|||
if ((result =
|
||||
openssl_SSL_ERROR_SSL(E_ERROR, "SSL_CTX_load_verify_locations"))
|
||||
!= STAT_OK) {
|
||||
/*! free ctx */
|
||||
SSL_CTX_free(*ctx); *ctx = NULL;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
|
@ -963,14 +1093,33 @@ static int xioSSL_set_fd(struct single *xfd, int level) {
|
|||
unsigned long err;
|
||||
|
||||
/* assign a network connection to the SSL object */
|
||||
if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->fd) <= 0) {
|
||||
if (xfd->fd2 < 0) {
|
||||
if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->fd1) <= 0) {
|
||||
Msg(level, "SSL_set_fd() failed");
|
||||
while (err = ERR_get_error()) {
|
||||
Msg2(level, "SSL_set_fd(, %d): %s",
|
||||
xfd->fd, ERR_error_string(err, NULL));
|
||||
xfd->fd2, ERR_error_string(err, NULL));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} else {
|
||||
if (sycSSL_set_rfd(xfd->para.openssl.ssl, xfd->fd1) <= 0) {
|
||||
Msg(level, "SSL_set_rfd() failed");
|
||||
while (err = ERR_get_error()) {
|
||||
Msg2(level, "SSL_set_rfd(, %d): %s",
|
||||
xfd->fd1, ERR_error_string(err, NULL));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
if (sycSSL_set_wfd(xfd->para.openssl.ssl, xfd->fd2) <= 0) {
|
||||
Msg(level, "SSL_set_wfd() failed");
|
||||
while (err = ERR_get_error()) {
|
||||
Msg2(level, "SSL_set_wfd(, %d): %s",
|
||||
xfd->fd2, ERR_error_string(err, NULL));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
#define SSLIO_BASE 0x53530000 /* "SSxx" */
|
||||
#define SSLIO_MASK 0xffff0000
|
||||
|
||||
extern const struct addrdesc addr_openssl;
|
||||
extern const struct addrdesc addr_openssl_listen;
|
||||
extern const union xioaddr_desc *xioaddrs_openssl_connect[];
|
||||
extern const union xioaddr_desc *xioaddrs_openssl_listen[];
|
||||
|
||||
extern const struct optdesc opt_openssl_cipherlist;
|
||||
extern const struct optdesc opt_openssl_method;
|
||||
|
|
48
xio-pipe.c
48
xio-pipe.c
|
@ -12,16 +12,20 @@
|
|||
|
||||
#if WITH_PIPE
|
||||
|
||||
static int xioopen_fifo(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts);
|
||||
static int xioopen_fifo0(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
static int xioopen_fifo1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
|
||||
static const struct xioaddr_endpoint_desc xioaddr_pipe0 = { XIOADDR_SYS, "pipe", 0, XIOBIT_RDWR, GROUP_FD|GROUP_NAMED|GROUP_OPEN|GROUP_FIFO, XIOSHUT_CLOSE, XIOCLOSE_CLOSE, xioopen_fifo0, 0, 0, 0 HELP("") };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_pipe1 = { XIOADDR_SYS, "pipe", 1, XIOBIT_ALL, GROUP_FD|GROUP_NAMED|GROUP_OPEN|GROUP_FIFO, XIOSHUT_CLOSE, XIOCLOSE_CLOSE, xioopen_fifo1, 0, 0, 0 HELP(":<filename>") };
|
||||
|
||||
const struct addrdesc addr_pipe = { "pipe", 3, xioopen_fifo, GROUP_FD|GROUP_NAMED|GROUP_OPEN|GROUP_FIFO, 0, 0, 0 HELP(":<filename>") };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_pipe[] = {
|
||||
(union xioaddr_desc *)&xioaddr_pipe0,
|
||||
(union xioaddr_desc *)&xioaddr_pipe1,
|
||||
NULL };
|
||||
|
||||
/* process an unnamed bidirectional "pipe" or "fifo" or "echo" argument with
|
||||
options */
|
||||
static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) {
|
||||
static int xioopen_fifo0(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *sock, unsigned groups, int dummy1, int dummy2, int dummy3) {
|
||||
struct opt *opts2;
|
||||
int filedes[2];
|
||||
int numleft;
|
||||
|
@ -37,11 +41,12 @@ static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) {
|
|||
/*0 Info2("pipe({%d,%d})", filedes[0], filedes[1]);*/
|
||||
|
||||
sock->common.tag = XIO_TAG_RDWR;
|
||||
sock->stream.dtype = XIODATA_PIPE;
|
||||
sock->stream.fd = filedes[0];
|
||||
sock->stream.para.bipipe.fdout = filedes[1];
|
||||
applyopts_cloexec(sock->stream.fd, opts);
|
||||
applyopts_cloexec(sock->stream.para.bipipe.fdout, opts);
|
||||
sock->stream.dtype = XIODATA_2PIPE;
|
||||
sock->stream.fd1 = filedes[0];
|
||||
sock->stream.fd2 = filedes[1];
|
||||
sock->stream.fdtype = FDTYPE_DOUBLE;
|
||||
applyopts_cloexec(sock->stream.fd1, opts);
|
||||
applyopts_cloexec(sock->stream.fd2, opts);
|
||||
|
||||
/* one-time and input-direction options, no second application */
|
||||
retropt_bool(opts, OPT_IGNOREEOF, &sock->stream.ignoreeof);
|
||||
|
@ -52,7 +57,7 @@ static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) {
|
|||
}
|
||||
|
||||
/* apply options to first FD */
|
||||
if ((result = applyopts(sock->stream.fd, opts, PH_ALL)) < 0) {
|
||||
if ((result = applyopts(sock->stream.fd1, opts, PH_ALL)) < 0) {
|
||||
return result;
|
||||
}
|
||||
if ((result = applyopts_single(&sock->stream, opts, PH_ALL)) < 0) {
|
||||
|
@ -60,7 +65,7 @@ static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) {
|
|||
}
|
||||
|
||||
/* apply options to second FD */
|
||||
if ((result = applyopts(sock->stream.para.bipipe.fdout, opts2, PH_ALL)) < 0)
|
||||
if ((result = applyopts(sock->stream.fd2, opts2, PH_ALL)) < 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
@ -75,7 +80,7 @@ static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) {
|
|||
|
||||
|
||||
/* open a named pipe/fifo */
|
||||
static int xioopen_fifo(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) {
|
||||
static int xioopen_fifo1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) {
|
||||
const char *pipename = argv[1];
|
||||
int rw = (xioflags & XIO_ACCMODE);
|
||||
#if HAVE_STAT64
|
||||
|
@ -88,14 +93,6 @@ static int xioopen_fifo(int argc, const char *argv[], struct opt *opts, int xiof
|
|||
mode_t mode = 0666;
|
||||
int result;
|
||||
|
||||
if (argc == 1) {
|
||||
return xioopen_fifo_unnamed(fd, fd->stream.opts);
|
||||
}
|
||||
|
||||
if (argc != 2) {
|
||||
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
|
||||
}
|
||||
|
||||
if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
|
@ -166,11 +163,14 @@ static int xioopen_fifo(int argc, const char *argv[], struct opt *opts, int xiof
|
|||
if ((result = _xioopen_open(pipename, rw, opts)) < 0) {
|
||||
return result;
|
||||
}
|
||||
fd->stream.fd = result;
|
||||
fd->stream.fd1 = result;
|
||||
fd->stream.fdtype = FDTYPE_SINGLE;
|
||||
fd->stream.howtoshut = XIOSHUTWR_NONE|XIOSHUTRD_CLOSE;
|
||||
fd->stream.howtoclose = XIOCLOSE_CLOSE;
|
||||
|
||||
applyopts_named(pipename, opts, PH_FD);
|
||||
applyopts(fd->stream.fd, opts, PH_FD);
|
||||
applyopts_cloexec(fd->stream.fd, opts);
|
||||
applyopts(fd->stream.fd1, opts, PH_FD);
|
||||
applyopts_cloexec(fd->stream.fd1, opts);
|
||||
return _xio_openlate(&fd->stream, opts);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/* $Id: xio-pipe.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001 */
|
||||
/* $Id: xio-pipe.h,v 1.4.2.1 2006/07/24 19:18:02 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_pipe_h_included
|
||||
#define __xio_pipe_h_included 1
|
||||
|
||||
const extern struct addrdesc addr_pipe;
|
||||
extern const union xioaddr_desc *xioaddrs_pipe[];
|
||||
|
||||
extern int xioopen_fifo_unnamed(char *arg, xiofile_t *sock);
|
||||
|
||||
|
|
760
xio-progcall.c
760
xio-progcall.c
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "xiosysincludes.h"
|
||||
#include "xioopen.h"
|
||||
#include "xiosigchld.h"
|
||||
|
||||
#include "xio-process.h"
|
||||
#include "xio-progcall.h"
|
||||
|
@ -41,7 +42,7 @@ const struct optdesc opt_sigquit = { "sigquit", NULL, OPT_SIGQUIT, GROUP_P
|
|||
return>0: is parent process
|
||||
return<0: error occurred, assume parent process and no child exists !!!
|
||||
*/
|
||||
int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
||||
int _xioopen_foxec_int(int xioflags, /* XIO_RDONLY etc. */
|
||||
struct single *fd,
|
||||
unsigned groups,
|
||||
struct opt **copts /* in: opts; out: opts for child */
|
||||
|
@ -102,6 +103,11 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
retropt_ushort(popts, OPT_FDIN, (unsigned short *)&fdi);
|
||||
retropt_ushort(popts, OPT_FDOUT, (unsigned short *)&fdo);
|
||||
|
||||
if (rw == XIO_WRONLY) {
|
||||
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
|
||||
fd->howtoclose = XIOCLOSE_SLEEP_SIGTERM;
|
||||
}
|
||||
}
|
||||
if (withfork) {
|
||||
if (!(xioflags&XIO_MAYCHILD)) {
|
||||
Error("cannot fork off child process here");
|
||||
|
@ -125,15 +131,24 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
if (!withfork) {
|
||||
/*0 struct single *stream1, *stream2;*/
|
||||
|
||||
free(*copts);
|
||||
*copts = moveopts(popts, GROUP_ALL);
|
||||
/* what if WE are sock1 ? */
|
||||
#if 1
|
||||
if (!(xioflags & XIO_MAYEXEC /* means exec+nofork */)) {
|
||||
Error("option nofork is not allowed here");
|
||||
Error("nofork option is not allowed here");
|
||||
/*!! free something */
|
||||
return -1;
|
||||
}
|
||||
fd->flags |= XIO_DOESEXEC;
|
||||
|
||||
free(*copts);
|
||||
*copts = moveopts(popts, GROUP_ALL);
|
||||
#else /*!! */
|
||||
if (sock1 == NULL) {
|
||||
Fatal("nofork option must no be applied to first socat address");
|
||||
}
|
||||
#endif
|
||||
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
|
||||
fd->howtoclose = XIOCLOSE_CLOSE;
|
||||
}
|
||||
|
||||
#if 0 /*!! */
|
||||
if (sock1->tag == XIO_TAG_DUAL) {
|
||||
|
@ -202,6 +217,13 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
# define PTMX "/dev/ptc" /* AIX 4.3.3 */
|
||||
#endif
|
||||
fd->dtype = XIODATA_PTY;
|
||||
if (fd->howtoshut == XIOSHUT_UNSPEC) {
|
||||
fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP;
|
||||
}
|
||||
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
|
||||
fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM;
|
||||
}
|
||||
|
||||
#if HAVE_DEV_PTMX || HAVE_DEV_PTC
|
||||
if (usebestpty || useptmx) {
|
||||
if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) {
|
||||
|
@ -235,7 +257,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
Warn2("ttyname(%d): %s", ptyfd, strerror(errno));
|
||||
}
|
||||
}
|
||||
strncpy(ptyname, tn, MAXPTYNAMELEN);
|
||||
strncpy(ptyname, tn, MAXPTYNAMELEN); /*! ttyname_r() */
|
||||
if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) {
|
||||
Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno));
|
||||
} else {
|
||||
|
@ -283,8 +305,11 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
return STAT_RETRYLATER;
|
||||
}
|
||||
applyopts_cloexec(ptyfd, popts);/*!*/
|
||||
if (fd->howtoend = END_UNSPEC) {
|
||||
fd->howtoend = END_CLOSE_KILL;
|
||||
if (fd->howtoshut == XIOSHUT_UNSPEC) {
|
||||
fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP;
|
||||
}
|
||||
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
|
||||
fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM;
|
||||
}
|
||||
|
||||
/* this for parent, was after fork */
|
||||
|
@ -292,7 +317,8 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
applyopts(ptyfd, popts, PH_LATE);
|
||||
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
|
||||
|
||||
fd->fd = ptyfd;
|
||||
fd->fd1 = ptyfd;
|
||||
fd->fdtype = FDTYPE_SINGLE;
|
||||
|
||||
/* this for child, was after fork */
|
||||
applyopts(ttyfd, *copts, PH_FD);
|
||||
|
@ -301,13 +327,23 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
if (usepipes) {
|
||||
struct opt *popts2, *copts2;
|
||||
|
||||
if (rw == XIO_RDWR)
|
||||
if (rw == XIO_RDWR) {
|
||||
fd->dtype = XIODATA_2PIPE;
|
||||
}
|
||||
if (fd->howtoshut == XIOSHUT_UNSPEC) {
|
||||
fd->howtoshut = XIOSHUT_CLOSE;
|
||||
}
|
||||
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
|
||||
fd->howtoclose = XIOCLOSE_CLOSE;
|
||||
}
|
||||
|
||||
if (rw != XIO_WRONLY) {
|
||||
if (Pipe(rdpip) < 0) {
|
||||
Error2("pipe(%p): %s", rdpip, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} else {
|
||||
rdpip[0] = rdpip[1] = -1;
|
||||
}
|
||||
/*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/
|
||||
/* rdpip[0]: read by socat; rdpip[1]: write by child */
|
||||
|
@ -331,6 +367,8 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
Error2("pipe(%p): %s", wrpip, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} else {
|
||||
wrpip[0] = wrpip[1] = -1;
|
||||
}
|
||||
/*0 Info2("pipe({%d,%d})", wrpip[0], wrpip[1]);*/
|
||||
|
||||
|
@ -340,20 +378,25 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
applyopts(wrpip[1], popts2, PH_FD);
|
||||
applyopts(wrpip[0], copts2, PH_FD);
|
||||
}
|
||||
if (fd->howtoend == END_UNSPEC) {
|
||||
fd->howtoend = END_CLOSE_KILL;
|
||||
}
|
||||
|
||||
/* this for parent, was after fork */
|
||||
switch (rw) {
|
||||
case XIO_RDONLY: fd->fd = rdpip[0]; break;
|
||||
case XIO_WRONLY: fd->fd = wrpip[1]; break;
|
||||
case XIO_RDWR: fd->fd = rdpip[0];
|
||||
fd->para.exec.fdout = wrpip[1];
|
||||
case XIO_RDONLY:
|
||||
fd->fd1 = rdpip[0];
|
||||
fd->fdtype = FDTYPE_SINGLE;
|
||||
break;
|
||||
case XIO_WRONLY:
|
||||
fd->fd1 = wrpip[1];
|
||||
fd->fdtype = FDTYPE_SINGLE;
|
||||
break;
|
||||
case XIO_RDWR:
|
||||
fd->fd1 = rdpip[0];
|
||||
fd->fd2 = wrpip[1];
|
||||
fd->fdtype = FDTYPE_DOUBLE;
|
||||
break;
|
||||
}
|
||||
applyopts(fd->fd, popts, PH_FD);
|
||||
applyopts(fd->fd, popts, PH_LATE);
|
||||
applyopts(fd->fd1, popts, PH_FD);
|
||||
applyopts(fd->fd1, popts, PH_LATE);
|
||||
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
|
||||
} else {
|
||||
d = AF_UNIX; type = SOCK_STREAM;
|
||||
|
@ -385,29 +428,42 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
applyopts(sv[1], popts, PH_BIND);
|
||||
applyopts(sv[1], popts, PH_PASTBIND);
|
||||
|
||||
if (fd->howtoend == END_UNSPEC) {
|
||||
fd->howtoend = END_SHUTDOWN_KILL;
|
||||
if (fd->howtoshut == XIOSHUT_UNSPEC) {
|
||||
fd->howtoshut = XIOSHUT_DOWN;
|
||||
}
|
||||
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
|
||||
fd->howtoclose = XIOCLOSE_SIGTERM;
|
||||
}
|
||||
|
||||
/* this for parent, was after fork */
|
||||
fd->fd = sv[0];
|
||||
applyopts(fd->fd, popts, PH_FD);
|
||||
applyopts(fd->fd, popts, PH_LATE);
|
||||
fd->fd1 = sv[0];
|
||||
fd->fdtype = FDTYPE_SINGLE;
|
||||
applyopts(fd->fd1, popts, PH_FD);
|
||||
applyopts(fd->fd1, popts, PH_LATE);
|
||||
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
|
||||
}
|
||||
/*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL)
|
||||
return STAT_RETRYLATER;*/
|
||||
retropt_bool(*copts, OPT_STDERR, &withstderr);
|
||||
#if 0
|
||||
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
|
||||
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (withfork) {
|
||||
const char *forkwaitstring;
|
||||
int forkwaitsecs = 0;
|
||||
sigset_t set, oldset;
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGCHLD);
|
||||
|
||||
Sigprocmask(SIG_BLOCK, &set, &oldset); /* disable SIGCHLD */
|
||||
|
||||
pid = Fork();
|
||||
if (pid < 0) {
|
||||
Sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||
Error1("fork(): %s", strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
@ -417,11 +473,18 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
Sleep(forkwaitsecs);
|
||||
}
|
||||
|
||||
if (pid > 0) {
|
||||
/* for parent (this is our socat process) */
|
||||
xiosigchld_register(pid, xiosigaction_child, fd);
|
||||
Sigprocmask(SIG_SETMASK, &oldset, NULL); /* disable SIGCHLD */
|
||||
}
|
||||
|
||||
if (pid == 0) { /* child */
|
||||
/* drop parents locks, reset FIPS... */
|
||||
if (xio_forked_inchild() != 0) {
|
||||
Exit(1);
|
||||
}
|
||||
Sigprocmask(SIG_SETMASK, &oldset, NULL); /* disable SIGCHLD */
|
||||
}
|
||||
}
|
||||
if (!withfork || pid == 0) { /* child */
|
||||
|
@ -580,19 +643,23 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
return STAT_RETRYLATER;
|
||||
#endif
|
||||
|
||||
if (0) {
|
||||
; /* for canonical reasons */
|
||||
#if HAVE_PTY
|
||||
if (usepty) {
|
||||
} else if (usepty) {
|
||||
if (Close(ttyfd) < 0) {
|
||||
Info2("close(%d): %s", ttyfd, strerror(errno));
|
||||
}
|
||||
} /*0 else*/
|
||||
#endif /* HAVE_PTY */
|
||||
#if 0
|
||||
if (usepipes) {
|
||||
} else {
|
||||
#if 1
|
||||
} else if (usepipes) {
|
||||
if (wrpip[0] >= 0) Close(wrpip[0]);
|
||||
if (rdpip[1] >= 0) Close(rdpip[1]);
|
||||
} else { /* socketpair() */
|
||||
Close(sv[1]);
|
||||
}
|
||||
#endif
|
||||
fd->para.exec.pid = pid;
|
||||
fd->child.pid = pid;
|
||||
|
||||
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
|
||||
applyopts_signal(fd, popts);
|
||||
|
@ -604,6 +671,639 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
|
||||
return pid; /* indicate parent (main) process */
|
||||
}
|
||||
|
||||
|
||||
/* fork for exec/system, but return before exec'ing.
|
||||
return=0: is child process
|
||||
return>0: is parent process
|
||||
return<0: error occurred, assume parent process and no child exists !!!
|
||||
*/
|
||||
int _xioopen_foxec_end(int xioflags, /* XIO_RDONLY etc. */
|
||||
struct single *fd,
|
||||
unsigned groups,
|
||||
struct opt **copts /* in: opts; out: opts for child */
|
||||
) {
|
||||
struct opt *popts; /* parent process options */
|
||||
int numleft;
|
||||
int d, type, protocol, sv[2], rdpip[2], wrpip[2];
|
||||
int rw = (xioflags & XIO_ACCMODE);
|
||||
bool usepipes = false;
|
||||
#if HAVE_PTY
|
||||
int ptyfd = -1, ttyfd = -1;
|
||||
bool usebestpty = false; /* use the best available way to open pty */
|
||||
#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
|
||||
bool useptmx = false; /* use /dev/ptmx or equivalent */
|
||||
#endif
|
||||
#if HAVE_OPENPTY
|
||||
bool useopenpty = false; /* try only openpty */
|
||||
#endif /* HAVE_OPENPTY */
|
||||
bool usepty = false; /* any of the pty options is selected */
|
||||
char ptyname[MAXPTYNAMELEN];
|
||||
#endif /* HAVE_PTY */
|
||||
pid_t pid = 0; /* mostly int */
|
||||
short fdi = 0, fdo = 1;
|
||||
short result;
|
||||
bool withstderr = false;
|
||||
bool nofork = false;
|
||||
bool withfork;
|
||||
|
||||
popts = moveopts(*copts, GROUP_ALL);
|
||||
if (applyopts_single(fd, popts, PH_INIT) < 0) return -1;
|
||||
applyopts2(-1, popts, PH_INIT, PH_EARLY);
|
||||
|
||||
retropt_bool(popts, OPT_NOFORK, &nofork);
|
||||
withfork = !nofork;
|
||||
|
||||
retropt_bool(popts, OPT_PIPES, &usepipes);
|
||||
#if HAVE_PTY
|
||||
retropt_bool(popts, OPT_PTY, &usebestpty);
|
||||
#if HAVE_OPENPTY
|
||||
retropt_bool(popts, OPT_OPENPTY, &useopenpty);
|
||||
#endif
|
||||
#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
|
||||
retropt_bool(popts, OPT_PTMX, &useptmx);
|
||||
#endif
|
||||
usepty = (usebestpty
|
||||
#if HAVE_OPENPTY
|
||||
|| useopenpty
|
||||
#endif
|
||||
#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
|
||||
|| useptmx
|
||||
#endif
|
||||
);
|
||||
if (usepipes && usepty) {
|
||||
Warn("_xioopen_foxec(): options \"pipes\" and \"pty\" must not be specified together; ignoring \"pipes\"");
|
||||
usepipes = false;
|
||||
}
|
||||
#endif /* HAVE_PTY */
|
||||
retropt_ushort(popts, OPT_FDIN, (unsigned short *)&fdi);
|
||||
retropt_ushort(popts, OPT_FDOUT, (unsigned short *)&fdo);
|
||||
|
||||
if (rw == XIO_WRONLY) {
|
||||
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
|
||||
fd->howtoclose = XIOCLOSE_SLEEP_SIGTERM;
|
||||
}
|
||||
}
|
||||
if (withfork) {
|
||||
if (!(xioflags&XIO_MAYCHILD)) {
|
||||
Error("cannot fork off child process here");
|
||||
/*!! free something */
|
||||
return -1;
|
||||
}
|
||||
fd->flags |= XIO_DOESCHILD;
|
||||
|
||||
#if HAVE_PTY
|
||||
Notice2("forking off child, using %s for %s",
|
||||
&("socket\0\0pipes\0\0\0pty\0\0\0\0\0"[(usepipes<<3)|(usepty<<4)]),
|
||||
ddirection[rw]);
|
||||
#else
|
||||
Notice2("forking off child, using %s for %s",
|
||||
&("socket\0\0pipes\0\0\0"[(usepipes<<3)]),
|
||||
ddirection[rw]);
|
||||
#endif /* HAVE_PTY */
|
||||
}
|
||||
applyopts(-1, popts, PH_PREBIGEN);
|
||||
|
||||
if (!withfork) {
|
||||
/*0 struct single *stream1, *stream2;*/
|
||||
|
||||
free(*copts);
|
||||
*copts = moveopts(popts, GROUP_ALL);
|
||||
/* what if WE are sock1 ? */
|
||||
#if 1
|
||||
if (!(xioflags & XIO_MAYEXEC /* means exec+nofork */)) {
|
||||
Error("nofork option is not allowed here");
|
||||
/*!! free something */
|
||||
return -1;
|
||||
}
|
||||
fd->flags |= XIO_DOESEXEC;
|
||||
#else /*!! */
|
||||
if (sock1 == NULL) {
|
||||
Fatal("nofork option must no be applied to first socat address");
|
||||
}
|
||||
#endif
|
||||
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
|
||||
fd->howtoclose = XIOCLOSE_CLOSE;
|
||||
}
|
||||
|
||||
#if 0 /*!! */
|
||||
if (sock1->tag == XIO_TAG_DUAL) {
|
||||
stream1 = &sock1->dual.stream[0]->stream;
|
||||
stream2 = &sock1->dual.stream[1]->stream;
|
||||
} else {
|
||||
stream1 = &sock1->stream;
|
||||
stream2 = &sock1->stream;
|
||||
}
|
||||
if (stream1->dtype == DATA_READLINE || stream2->dtype == DATA_READLINE ||
|
||||
stream1->dtype == DATA_OPENSSL || stream2->dtype == DATA_OPENSSL
|
||||
) {
|
||||
Error("with option nofork, openssl and readline in address1 do not work");
|
||||
}
|
||||
if (stream1->lineterm != LINETERM_RAW ||
|
||||
stream2->lineterm != LINETERM_RAW ||
|
||||
stream1->ignoreeof || stream2->ignoreeof) {
|
||||
Warn("due to option nofork, address1 options for lineterm and igoreeof do not apply");
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! problem: when fdi==WRFD(sock[0]) or fdo==RDFD(sock[0]) */
|
||||
if (rw != XIO_WRONLY) {
|
||||
if (XIO_GETRDFD(sock[0]/*!!*/) == fdi) {
|
||||
if (Fcntl_l(fdi, F_SETFD, 0) < 0) {
|
||||
Warn2("fcntl(%d, F_SETFD, 0): %s", fdi, strerror(errno));
|
||||
}
|
||||
if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) {
|
||||
Error3("dup2(%d, %d): %s",
|
||||
XIO_GETRDFD(sock[0]), fdi, strerror(errno));
|
||||
}
|
||||
/*0 Info2("dup2(%d, %d)", XIO_GETRDFD(sock[0]), fdi);*/
|
||||
} else {
|
||||
if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) {
|
||||
Error3("dup2(%d, %d): %s",
|
||||
XIO_GETRDFD(sock[0]), fdi, strerror(errno));
|
||||
}
|
||||
/*0 Info2("dup2(%d, %d)", XIO_GETRDFD(sock[0]), fdi);*/
|
||||
}
|
||||
}
|
||||
if (rw != XIO_RDONLY) {
|
||||
if (XIO_GETWRFD(sock[0]) == fdo) {
|
||||
if (Fcntl_l(fdo, F_SETFD, 0) < 0) {
|
||||
Warn2("fcntl(%d, F_SETFD, 0): %s", fdo, strerror(errno));
|
||||
}
|
||||
if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) {
|
||||
Error3("dup2(%d, %d): %s)",
|
||||
XIO_GETWRFD(sock[0]), fdo, strerror(errno));
|
||||
}
|
||||
/*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/
|
||||
} else {
|
||||
if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) {
|
||||
Error3("dup2(%d, %d): %s)",
|
||||
XIO_GETWRFD(sock[0]), fdo, strerror(errno));
|
||||
}
|
||||
/*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/
|
||||
}
|
||||
}
|
||||
} else
|
||||
#if HAVE_PTY
|
||||
if (usepty) {
|
||||
|
||||
#if defined(HAVE_DEV_PTMX)
|
||||
# define PTMX "/dev/ptmx" /* Linux */
|
||||
#elif HAVE_DEV_PTC
|
||||
# define PTMX "/dev/ptc" /* AIX 4.3.3 */
|
||||
#endif
|
||||
fd->dtype = XIODATA_PTY;
|
||||
if (fd->howtoshut == XIOSHUT_UNSPEC) {
|
||||
fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP;
|
||||
}
|
||||
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
|
||||
fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM;
|
||||
}
|
||||
|
||||
#if HAVE_DEV_PTMX || HAVE_DEV_PTC
|
||||
if (usebestpty || useptmx) {
|
||||
if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) {
|
||||
Warn1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620): %s",
|
||||
strerror(errno));
|
||||
/*!*/
|
||||
} else {
|
||||
/*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", PTMX, ptyfd);*/
|
||||
}
|
||||
if (ptyfd >= 0 && ttyfd < 0) {
|
||||
char *tn = NULL;
|
||||
/* we used PTMX before forking */
|
||||
extern char *ptsname(int);
|
||||
#if HAVE_GRANTPT /* AIX, not Linux */
|
||||
if (Grantpt(ptyfd)/*!*/ < 0) {
|
||||
Warn2("grantpt(%d): %s", ptyfd, strerror(errno));
|
||||
}
|
||||
#endif /* HAVE_GRANTPT */
|
||||
#if HAVE_UNLOCKPT
|
||||
if (Unlockpt(ptyfd)/*!*/ < 0) {
|
||||
Warn2("unlockpt(%d): %s", ptyfd, strerror(errno));
|
||||
}
|
||||
#endif /* HAVE_UNLOCKPT */
|
||||
#if HAVE_PTSNAME /* AIX, not Linux */
|
||||
if ((tn = Ptsname(ptyfd)) == NULL) {
|
||||
Warn2("ptsname(%d): %s", ptyfd, strerror(errno));
|
||||
}
|
||||
#endif /* HAVE_PTSNAME */
|
||||
if (tn == NULL) {
|
||||
if ((tn = Ttyname(ptyfd)) == NULL) {
|
||||
Warn2("ttyname(%d): %s", ptyfd, strerror(errno));
|
||||
}
|
||||
}
|
||||
strncpy(ptyname, tn, MAXPTYNAMELEN); /*! ttyname_r() */
|
||||
if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) {
|
||||
Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno));
|
||||
} else {
|
||||
/*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/
|
||||
}
|
||||
|
||||
#ifdef I_PUSH
|
||||
/* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */
|
||||
/* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */
|
||||
/* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
|
||||
/* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
|
||||
if (Ioctl(ttyfd, I_FIND, "ldterm") == 0) {
|
||||
Ioctl(ttyfd, I_PUSH, "ptem"); /* 0 */
|
||||
Ioctl(ttyfd, I_PUSH, "ldterm"); /* 0 */
|
||||
Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 /* the following block need not work */
|
||||
|
||||
if (ttyfd >= 0 && ((tn = Ttyname(ttyfd)) == NULL)) {
|
||||
Warn2("ttyname(%d): %s", ttyfd, strerror(errno));
|
||||
}
|
||||
if (tn == NULL) {
|
||||
Error("could not open pty");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
#endif
|
||||
Info1("opened pseudo terminal %s", tn);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */
|
||||
#if HAVE_OPENPTY
|
||||
if (ptyfd < 0) {
|
||||
int result;
|
||||
if ((result = Openpty(&ptyfd, &ttyfd, ptyname, NULL, NULL)) < 0) {
|
||||
Error4("openpty(%p, %p, %p, NULL, NULL): %s",
|
||||
&ptyfd, &ttyfd, ptyname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_OPENPTY */
|
||||
free(*copts);
|
||||
if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
applyopts_cloexec(ptyfd, popts);/*!*/
|
||||
if (fd->howtoshut == XIOSHUT_UNSPEC) {
|
||||
fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP;
|
||||
}
|
||||
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
|
||||
fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM;
|
||||
}
|
||||
|
||||
/* this for parent, was after fork */
|
||||
applyopts(ptyfd, popts, PH_FD);
|
||||
applyopts(ptyfd, popts, PH_LATE);
|
||||
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
|
||||
|
||||
fd->fd1 = ptyfd;
|
||||
fd->fdtype = FDTYPE_SINGLE;
|
||||
|
||||
/* this for child, was after fork */
|
||||
applyopts(ttyfd, *copts, PH_FD);
|
||||
} else
|
||||
#endif /* HAVE_PTY */
|
||||
if (usepipes) {
|
||||
struct opt *popts2, *copts2;
|
||||
|
||||
if (rw == XIO_RDWR) {
|
||||
fd->dtype = XIODATA_2PIPE;
|
||||
}
|
||||
if (fd->howtoshut == XIOSHUT_UNSPEC) {
|
||||
fd->howtoshut = XIOSHUT_CLOSE;
|
||||
}
|
||||
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
|
||||
fd->howtoclose = XIOCLOSE_CLOSE;
|
||||
}
|
||||
|
||||
if (rw != XIO_WRONLY) {
|
||||
if (Pipe(rdpip) < 0) {
|
||||
Error2("pipe(%p): %s", rdpip, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
/*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/
|
||||
/* rdpip[0]: read by socat; rdpip[1]: write by child */
|
||||
free(*copts);
|
||||
if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS))
|
||||
== NULL) {
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
popts2 = copyopts(popts, GROUP_ALL);
|
||||
copts2 = copyopts(*copts, GROUP_ALL);
|
||||
|
||||
if (rw != XIO_WRONLY) {
|
||||
applyopts_cloexec(rdpip[0], popts);
|
||||
applyopts(rdpip[0], popts, PH_FD);
|
||||
applyopts(rdpip[1], *copts, PH_FD);
|
||||
}
|
||||
|
||||
if (rw != XIO_RDONLY) {
|
||||
if (Pipe(wrpip) < 0) {
|
||||
Error2("pipe(%p): %s", wrpip, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
/*0 Info2("pipe({%d,%d})", wrpip[0], wrpip[1]);*/
|
||||
|
||||
/* wrpip[1]: write by socat; wrpip[0]: read by child */
|
||||
if (rw != XIO_RDONLY) {
|
||||
applyopts_cloexec(wrpip[1], popts2);
|
||||
applyopts(wrpip[1], popts2, PH_FD);
|
||||
applyopts(wrpip[0], copts2, PH_FD);
|
||||
}
|
||||
|
||||
/* this for parent, was after fork */
|
||||
switch (rw) {
|
||||
case XIO_RDONLY:
|
||||
fd->fd1 = rdpip[0];
|
||||
fd->fdtype = FDTYPE_SINGLE;
|
||||
break;
|
||||
case XIO_WRONLY:
|
||||
fd->fd1 = wrpip[1];
|
||||
fd->fdtype = FDTYPE_SINGLE;
|
||||
break;
|
||||
case XIO_RDWR:
|
||||
fd->fd1 = rdpip[0];
|
||||
fd->fd2 = wrpip[1];
|
||||
fd->fdtype = FDTYPE_DOUBLE;
|
||||
break;
|
||||
}
|
||||
applyopts(fd->fd1, popts, PH_FD);
|
||||
applyopts(fd->fd1, popts, PH_LATE);
|
||||
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
|
||||
} else {
|
||||
d = AF_UNIX; type = SOCK_STREAM;
|
||||
protocol = 0; /* PF_UNIX does not work on AIX */
|
||||
retropt_int(popts, OPT_SO_TYPE, &type);
|
||||
result = Socketpair(d, type, protocol, sv);
|
||||
if (result < 0) {
|
||||
Error5("socketpair(%d, %d, %d, %p): %s",
|
||||
d, type, protocol, sv, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
/*0 Info5("socketpair(%d, %d, %d, {%d,%d})",
|
||||
d, type, protocol, sv[0], sv[1]);*/
|
||||
free(*copts);
|
||||
if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
applyopts(sv[0], *copts, PH_PASTSOCKET);
|
||||
applyopts(sv[1], popts, PH_PASTSOCKET);
|
||||
|
||||
applyopts_cloexec(sv[0], *copts);
|
||||
applyopts(sv[0], *copts, PH_FD);
|
||||
applyopts(sv[1], popts, PH_FD);
|
||||
|
||||
applyopts(sv[0], *copts, PH_PREBIND);
|
||||
applyopts(sv[0], *copts, PH_BIND);
|
||||
applyopts(sv[0], *copts, PH_PASTBIND);
|
||||
applyopts(sv[1], popts, PH_PREBIND);
|
||||
applyopts(sv[1], popts, PH_BIND);
|
||||
applyopts(sv[1], popts, PH_PASTBIND);
|
||||
|
||||
if (fd->howtoshut == XIOSHUT_UNSPEC) {
|
||||
fd->howtoshut = XIOSHUT_DOWN;
|
||||
}
|
||||
if (fd->howtoclose == XIOCLOSE_UNSPEC) {
|
||||
fd->howtoclose = XIOCLOSE_SIGTERM;
|
||||
}
|
||||
|
||||
/* this for parent, was after fork */
|
||||
fd->fd1 = sv[0];
|
||||
fd->fdtype = FDTYPE_SINGLE;
|
||||
applyopts(fd->fd1, popts, PH_FD);
|
||||
applyopts(fd->fd1, popts, PH_LATE);
|
||||
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
|
||||
}
|
||||
/*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL)
|
||||
return STAT_RETRYLATER;*/
|
||||
retropt_bool(*copts, OPT_STDERR, &withstderr);
|
||||
#if 0
|
||||
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
|
||||
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (withfork) {
|
||||
const char *forkwaitstring;
|
||||
int forkwaitsecs = 0;
|
||||
sigset_t set, oldset;
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGCHLD);
|
||||
|
||||
Sigprocmask(SIG_BLOCK, &set, &oldset); /* disable SIGCHLD */
|
||||
|
||||
pid = Fork();
|
||||
if (pid < 0) {
|
||||
Sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||
Error1("fork(): %s", strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
/* gdb recommends to have env controlled sleep after fork */
|
||||
if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
|
||||
forkwaitsecs = atoi(forkwaitstring);
|
||||
Sleep(forkwaitsecs);
|
||||
}
|
||||
|
||||
if (pid > 0) {
|
||||
/* for parent (this is our socat process) */
|
||||
xiosigchld_register(pid, xiosigaction_child, fd);
|
||||
Sigprocmask(SIG_SETMASK, &oldset, NULL); /* disable SIGCHLD */
|
||||
}
|
||||
|
||||
if (pid == 0) { /* child */
|
||||
/* drop parents locks, reset FIPS... */
|
||||
if (xio_forked_inchild() != 0) {
|
||||
Exit(1);
|
||||
}
|
||||
Sigprocmask(SIG_SETMASK, &oldset, NULL); /* disable SIGCHLD */
|
||||
}
|
||||
}
|
||||
if (!withfork || pid == 0) { /* child */
|
||||
uid_t user;
|
||||
gid_t group;
|
||||
|
||||
if (withfork) {
|
||||
if (Signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
|
||||
Warn1("signal(SIGCHLD, SIG_IGN): %s", strerror(errno));
|
||||
}
|
||||
|
||||
#if HAVE_PTY
|
||||
if (usepty) {
|
||||
if (rw != XIO_RDONLY && fdi != ttyfd) {
|
||||
if (Dup2(ttyfd, fdi) < 0) {
|
||||
Error3("dup2(%d, %d): %s", ttyfd, fdi, strerror(errno));
|
||||
return STAT_RETRYLATER; }
|
||||
/*0 Info2("dup2(%d, %d)", ttyfd, fdi);*/
|
||||
}
|
||||
if (rw != XIO_WRONLY && fdo != ttyfd) {
|
||||
if (Dup2(ttyfd, fdo) < 0) {
|
||||
Error3("dup2(%d, %d): %s", ttyfd, fdo, strerror(errno));
|
||||
return STAT_RETRYLATER; }
|
||||
/*0 Info2("dup2(%d, %d)", ttyfd, fdo);*/
|
||||
}
|
||||
if ((rw == XIO_RDONLY || fdi != ttyfd) &&
|
||||
(rw == XIO_WRONLY || fdo != ttyfd)) {
|
||||
applyopts_cloexec(ttyfd, *copts);
|
||||
}
|
||||
|
||||
applyopts(ttyfd, *copts, PH_LATE);
|
||||
|
||||
applyopts(ttyfd, *copts, PH_LATE2);
|
||||
} else
|
||||
#endif /* HAVE_PTY */
|
||||
if (usepipes) {
|
||||
/* we might have a temporary conflict between what FDs are
|
||||
currently allocated, and which are to be used. We try to find
|
||||
a graceful solution via temporary descriptors */
|
||||
int tmpi, tmpo;
|
||||
|
||||
if (fdi == rdpip[1]) { /* a conflict here */
|
||||
if ((tmpi = Dup(wrpip[0])) < 0) {
|
||||
Error2("dup(%d): %s", wrpip[0], strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
/*0 Info2("dup(%d) -> %d", wrpip[0], tmpi);*/
|
||||
rdpip[1] = tmpi;
|
||||
}
|
||||
if (fdo == wrpip[0]) { /* a conflict here */
|
||||
if ((tmpo = Dup(rdpip[1])) < 0) {
|
||||
Error2("dup(%d): %s", rdpip[1], strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
/*0 Info2("dup(%d) -> %d", rdpip[1], tmpo);*/
|
||||
wrpip[0] = tmpo;
|
||||
}
|
||||
|
||||
if (rw != XIO_WRONLY && rdpip[1] != fdo) {
|
||||
if (Dup2(rdpip[1], fdo) < 0) {
|
||||
Error3("dup2(%d, %d): %s", rdpip[1], fdo, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
Close(rdpip[1]);
|
||||
/*0 Info2("dup2(%d, %d)", rdpip[1], fdo);*/
|
||||
/*0 applyopts_cloexec(fdo, *copts);*/
|
||||
}
|
||||
if (rw != XIO_RDONLY && wrpip[0] != fdi) {
|
||||
if (Dup2(wrpip[0], fdi) < 0) {
|
||||
Error3("dup2(%d, %d): %s", wrpip[0], fdi, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
Close(wrpip[0]);
|
||||
/*0 Info2("dup2(%d, %d)", wrpip[0], fdi);*/
|
||||
/*0 applyopts_cloexec(wrpip[0], *copts);*/ /* option is already consumed! */
|
||||
/* applyopts_cloexec(fdi, *copts);*/ /* option is already consumed! */
|
||||
}
|
||||
|
||||
applyopts(fdi, *copts, PH_LATE);
|
||||
applyopts(fdo, *copts, PH_LATE);
|
||||
applyopts(fdi, *copts, PH_LATE2);
|
||||
applyopts(fdo, *copts, PH_LATE2);
|
||||
|
||||
} else { /* socketpair */
|
||||
if (rw != XIO_RDONLY && fdi != sv[1]) {
|
||||
if (Dup2(sv[1], fdi) < 0) {
|
||||
Error3("dup2(%d, %d): %s", sv[1], fdi, strerror(errno));
|
||||
return STAT_RETRYLATER; }
|
||||
/*0 Info2("dup2(%d, %d)", sv[1], fdi);*/
|
||||
}
|
||||
if (rw != XIO_WRONLY && fdo != sv[1]) {
|
||||
if (Dup2(sv[1], fdo) < 0) {
|
||||
Error3("dup2(%d, %d): %s", sv[1], fdo, strerror(errno));
|
||||
return STAT_RETRYLATER; }
|
||||
/*0 Info2("dup2(%d, %d)", sv[1], fdo);*/
|
||||
}
|
||||
if (fdi != sv[1] && fdo != sv[1]) {
|
||||
applyopts_cloexec(sv[1], *copts);
|
||||
}
|
||||
|
||||
applyopts(fdi, *copts, PH_LATE);
|
||||
applyopts(fdi, *copts, PH_LATE2);
|
||||
}
|
||||
} /* withfork */
|
||||
else {
|
||||
applyopts(-1, *copts, PH_LATE);
|
||||
applyopts(-1, *copts, PH_LATE2);
|
||||
}
|
||||
|
||||
/* what to do with stderr? */
|
||||
if (withstderr) {
|
||||
/* handle it just like ordinary process output, i.e. copy output fd */
|
||||
if (!withfork) {
|
||||
if (Dup2(fdo, 2) < 0) {
|
||||
Error2("dup2(%d, 2): %s", fdo, strerror(errno));
|
||||
}
|
||||
/*0 Info1("dup2(%d, 2)", fdo);*/
|
||||
} else
|
||||
#if HAVE_PTY
|
||||
if (usepty) {
|
||||
if (Dup2(ttyfd, 2) < 0) {
|
||||
Error2("dup2(%d, 2): %s", ttyfd, strerror(errno));
|
||||
}
|
||||
/*0 Info1("dup2(%d, 2)", ttyfd);*/
|
||||
} else
|
||||
#endif /* HAVE_PTY */
|
||||
if (usepipes) {
|
||||
if (Dup2(/*rdpip[1]*/ fdo, 2) < 0) {
|
||||
Error2("dup2(%d, 2): %s", /*rdpip[1]*/ fdo, strerror(errno));
|
||||
}
|
||||
/*0 Info1("dup2(%d, 2)", rdpip[1]);*/
|
||||
} else {
|
||||
if (Dup2(sv[1], 2) < 0) {
|
||||
Error2("dup2(%d, 2): %s", sv[1], strerror(errno));
|
||||
}
|
||||
/*0 Info1("dup2(%d, 2)", sv[1]);*/
|
||||
}
|
||||
}
|
||||
_xioopen_setdelayeduser();
|
||||
/* set group before user - maybe you are not permitted afterwards */
|
||||
if (retropt_gidt(*copts, OPT_SETGID, &group) >= 0) {
|
||||
Setgid(group);
|
||||
}
|
||||
if (retropt_uidt(*copts, OPT_SETUID, &user) >= 0) {
|
||||
Setuid(user);
|
||||
}
|
||||
return 0; /* indicate child process */
|
||||
}
|
||||
|
||||
/* for parent (this is our socat process) */
|
||||
Notice1("forked off child process "F_pid, pid);
|
||||
|
||||
#if 0
|
||||
if ((popts = copyopts(*copts,
|
||||
GROUP_FD|GROUP_TERMIOS|GROUP_FORK|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_FIFO)) == NULL)
|
||||
return STAT_RETRYLATER;
|
||||
#endif
|
||||
|
||||
if (0) {
|
||||
; /* for canonical reasons */
|
||||
#if HAVE_PTY
|
||||
} else if (usepty) {
|
||||
if (Close(ttyfd) < 0) {
|
||||
Info2("close(%d): %s", ttyfd, strerror(errno));
|
||||
}
|
||||
#endif /* HAVE_PTY */
|
||||
#if 1
|
||||
} else if (usepipes) {
|
||||
Close(wrpip[0]);
|
||||
Close(rdpip[1]);
|
||||
} else { /* socketpair() */
|
||||
Close(sv[1]);
|
||||
}
|
||||
#endif
|
||||
fd->child.pid = pid;
|
||||
|
||||
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
|
||||
applyopts_signal(fd, popts);
|
||||
if ((numleft = leftopts(popts)) > 0) {
|
||||
Error1("%d option(s) could not be used", numleft);
|
||||
showleft(popts);
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
return pid; /* indicate parent (main) process */
|
||||
}
|
||||
|
||||
#endif /* WITH_EXEC || WITH_SYSTEM */
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xio-progcall.h,v 1.13 2006/02/08 19:37:15 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_progcall_h_included
|
||||
|
@ -18,7 +18,12 @@ extern const struct optdesc opt_sighup;
|
|||
extern const struct optdesc opt_sigint;
|
||||
extern const struct optdesc opt_sigquit;
|
||||
|
||||
extern int _xioopen_foxec(int rw, /* O_RDONLY etc. */
|
||||
extern int _xioopen_foxec_int(int rw, /* O_RDONLY etc. */
|
||||
struct single *fd,
|
||||
unsigned groups,
|
||||
struct opt **opts
|
||||
);
|
||||
extern int _xioopen_foxec_end(int rw, /* O_RDONLY etc. */
|
||||
struct single *fd,
|
||||
unsigned groups,
|
||||
struct opt **opts
|
||||
|
|
135
xio-proxy.c
135
xio-proxy.c
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xio-proxy.c,v 1.28 2006/12/28 14:02:54 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2002-2006 */
|
||||
/* Copyright Gerhard Rieger 2002-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for opening addresses of HTTP proxy CONNECT
|
||||
|
@ -19,8 +19,12 @@
|
|||
|
||||
#define PROXYPORT "8080"
|
||||
|
||||
static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *fd,
|
||||
static int xioopen_proxy_connect2(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups, int dummy1, int dummy2,
|
||||
int dummy3);
|
||||
static int xioopen_proxy_connect3(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups, int dummy1, int dummy2,
|
||||
int dummy3);
|
||||
|
||||
|
@ -29,8 +33,15 @@ const struct optdesc opt_ignorecr = { "ignorecr", NULL, OPT_IGNORECR, GROUP_H
|
|||
const struct optdesc opt_proxy_resolve = { "proxy-resolve", "resolve", OPT_PROXY_RESOLVE, GROUP_HTTP, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
|
||||
const struct optdesc opt_proxy_authorization = { "proxy-authorization", "proxyauth", OPT_PROXY_AUTHORIZATION, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC };
|
||||
|
||||
const struct addrdesc addr_proxy_connect = { "proxy", 3, xioopen_proxy_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_HTTP|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<proxy-server>:<host>:<port>") };
|
||||
static const struct xioaddr_inter_desc xioaddr_proxy_connect2 = { XIOADDR_INTER, "proxy", 2, XIOBIT_ALL, GROUP_HTTP|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_proxy_connect2, 0, 0, 0, XIOBIT_RDWR HELP(":<host>:<port>") };
|
||||
|
||||
static const struct xioaddr_endpoint_desc xioaddr_proxy_connect3 = { XIOADDR_ENDPOINT, "proxy", 3, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_HTTP|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_proxy_connect3, 0, 0, 0 HELP(":<proxy-server>:<host>:<port>") };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_proxy_connect[] = {
|
||||
(union xioaddr_desc *)&xioaddr_proxy_connect2,
|
||||
(union xioaddr_desc *)&xioaddr_proxy_connect3,
|
||||
NULL
|
||||
};
|
||||
|
||||
/*0#define CONNLEN 40*/ /* "CONNECT 123.156.189.123:65432 HTTP/1.0\r\n\0" */
|
||||
#define CONNLEN 281 /* "CONNECT <255bytes>:65432 HTTP/1.0\r\n\0" */
|
||||
|
@ -57,12 +68,12 @@ static ssize_t
|
|||
xioproxy_recvbytes(struct single *xfd, char *buff, size_t buflen, int level) {
|
||||
ssize_t result;
|
||||
do {
|
||||
/* we need at least buflen bytes... */
|
||||
result = Read(xfd->fd, buff, buflen);
|
||||
/* we need at least 16 bytes... */
|
||||
result = Read(xfd->fd1, buff, buflen);
|
||||
} while (result < 0 && errno == EINTR); /*! EAGAIN? */
|
||||
if (result < 0) {
|
||||
Msg4(level, "read(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd, buff, buflen, strerror(errno));
|
||||
xfd->fd1, buff, buflen, strerror(errno));
|
||||
return result;
|
||||
}
|
||||
if (result == 0) {
|
||||
|
@ -75,46 +86,105 @@ static ssize_t
|
|||
#define BUFLEN 2048
|
||||
|
||||
|
||||
static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
|
||||
static int xioopen_proxy_connect2(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups, int dummy1, int dummy2,
|
||||
int dummy3) {
|
||||
struct single *xfd = &xxfd->stream;
|
||||
struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars;
|
||||
const char *targetname, *targetport;
|
||||
/* variables to be filled with address option values */
|
||||
bool dofork = false;
|
||||
int result;
|
||||
|
||||
if (xfd->fd1 < 0) {
|
||||
Error("xioopen_proxy_connect(): proxyname missing");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
targetname = argv[1];
|
||||
targetport = argv[2];
|
||||
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
retropt_bool(opts, OPT_FORK, &dofork);
|
||||
if (dofork && !(xioflags & XIO_MAYFORK)) {
|
||||
Error("fork option not allowed by application");
|
||||
}
|
||||
|
||||
result = _xioopen_proxy_prepare(proxyvars, opts, targetname, targetport);
|
||||
if (result != STAT_OK) return result;
|
||||
|
||||
Notice2("opening connection to %s:%u using proxy CONNECT",
|
||||
proxyvars->targetaddr, proxyvars->targetport);
|
||||
|
||||
xfd->dtype = XIODATA_STREAM;
|
||||
xfd->fdtype = FDTYPE_DOUBLE;
|
||||
|
||||
applyopts(xfd->fd1, opts, PH_ALL);
|
||||
/*!*/
|
||||
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
return result;
|
||||
|
||||
result = _xioopen_proxy_connect(xfd, proxyvars, E_ERROR);
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
|
||||
Notice2("successfully connected to %s:%u via proxy",
|
||||
proxyvars->targetaddr, proxyvars->targetport);
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
static int xioopen_proxy_connect3(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups, int dummy1, int dummy2,
|
||||
int dummy3) {
|
||||
/* we expect the form: host:host:port */
|
||||
struct single *xfd = &xxfd->stream;
|
||||
struct opt *opts0 = NULL;
|
||||
struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars;
|
||||
const char *proxyname;
|
||||
char *proxyport = NULL;
|
||||
const char *targetname, *targetport;
|
||||
/* variables to be filled with address option values */
|
||||
bool dofork = false;
|
||||
int socktype = SOCK_STREAM;
|
||||
struct opt *opts0 = NULL;
|
||||
/* */
|
||||
int pf = PF_UNSPEC;
|
||||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
union sockaddr_union them_sa, *them = &them_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
socklen_t themlen = sizeof(them_sa);
|
||||
const char *proxyname; char *proxyport = NULL;
|
||||
const char *targetname, *targetport;
|
||||
int ipproto = IPPROTO_TCP;
|
||||
bool needbind = false;
|
||||
bool lowport = false;
|
||||
int socktype = SOCK_STREAM;
|
||||
int level;
|
||||
int result;
|
||||
|
||||
if (argc != 4) {
|
||||
Error1("%s: 3 parameters required", argv[0]);
|
||||
if (xfd->fd1 >= 0) {
|
||||
Error("xioopen_proxy_connect(): proxyname not allowed here");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
proxyname = argv[1];
|
||||
targetname = argv[2];
|
||||
targetport = argv[3];
|
||||
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
xfd->howtoshut = XIOSHUT_DOWN;
|
||||
xfd->howtoclose = XIOCLOSE_CLOSE;
|
||||
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
||||
|
||||
retropt_bool(opts, OPT_FORK, &dofork);
|
||||
if (dofork && !(xioflags & XIO_MAYFORK)) {
|
||||
Error("fork option not allowed by application");
|
||||
}
|
||||
|
||||
if (retropt_string(opts, OPT_PROXYPORT, &proxyport) < 0) {
|
||||
if ((proxyport = strdup(PROXYPORT)) == NULL) {
|
||||
|
@ -133,7 +203,6 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
|
|||
them, &themlen, us, &uslen,
|
||||
&needbind, &lowport, &socktype);
|
||||
if (result != STAT_OK) return result;
|
||||
|
||||
Notice4("opening connection to %s:%u via proxy %s:%s",
|
||||
proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport);
|
||||
|
||||
|
@ -164,8 +233,9 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
|
|||
default:
|
||||
return result;
|
||||
}
|
||||
|
||||
applyopts(xfd->fd, opts, PH_ALL);
|
||||
xfd->fdtype = FDTYPE_SINGLE;
|
||||
applyopts(xfd->fd1, opts, PH_ALL);
|
||||
/*!*/
|
||||
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
return result;
|
||||
|
@ -212,7 +282,8 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
|
|||
}
|
||||
/* parent process */
|
||||
Notice1("forked off child process "F_pid, pid);
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->fd2);
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
continue;
|
||||
|
@ -224,9 +295,8 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
|
|||
|
||||
} while (true); /* end of complete open loop - drop out on success */
|
||||
|
||||
Notice4("successfully connected to %s:%u via proxy %s:%s",
|
||||
proxyvars->targetaddr, proxyvars->targetport,
|
||||
proxyname, proxyport);
|
||||
Notice2("successfully connected to %s:%u via proxy",
|
||||
proxyvars->targetaddr, proxyvars->targetport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -275,6 +345,7 @@ int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts,
|
|||
int _xioopen_proxy_connect(struct single *xfd,
|
||||
struct proxyvars *proxyvars,
|
||||
int level) {
|
||||
int wfd;
|
||||
size_t offset;
|
||||
char request[CONNLEN];
|
||||
char buff[BUFLEN+1];
|
||||
|
@ -286,6 +357,8 @@ int _xioopen_proxy_connect(struct single *xfd,
|
|||
int state;
|
||||
ssize_t sresult;
|
||||
|
||||
wfd = (xfd->fdtype == FDTYPE_SINGLE ? xfd->fd1 : xfd->fd2);
|
||||
|
||||
/* generate proxy request header - points to final target */
|
||||
sprintf(request, "CONNECT %s:%u HTTP/1.0\r\n",
|
||||
proxyvars->targetaddr, proxyvars->targetport);
|
||||
|
@ -295,13 +368,13 @@ int _xioopen_proxy_connect(struct single *xfd,
|
|||
Info1("sending \"%s\"", textbuff);
|
||||
/* write errors are assumed to always be hard errors, no retry */
|
||||
do {
|
||||
sresult = Write(xfd->fd, request, strlen(request));
|
||||
sresult = Write(wfd, request, strlen(request));
|
||||
} while (sresult < 0 && errno == EINTR);
|
||||
if (sresult < 0) {
|
||||
Msg4(level, "write(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd, request, strlen(request), strerror(errno));
|
||||
if (Close(xfd->fd) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd, strerror(errno));
|
||||
wfd, request, strlen(request), strerror(errno));
|
||||
if (Close(wfd) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
@ -328,13 +401,13 @@ int _xioopen_proxy_connect(struct single *xfd,
|
|||
Info1("sending \"%s\\r\\n\"", header);
|
||||
*next++ = '\r'; *next++ = '\n'; *next++ = '\0';
|
||||
do {
|
||||
sresult = Write(xfd->fd, header, strlen(header));
|
||||
sresult = Write(wfd, header, strlen(header));
|
||||
} while (sresult < 0 && errno == EINTR);
|
||||
if (sresult < 0) {
|
||||
Msg4(level, "write(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd, header, strlen(header), strerror(errno));
|
||||
if (Close(xfd->fd) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd, strerror(errno));
|
||||
xfd->fd2, header, strlen(header), strerror(errno));
|
||||
if (Close(wfd/*!*/) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
@ -344,7 +417,7 @@ int _xioopen_proxy_connect(struct single *xfd,
|
|||
|
||||
Info("sending \"\\r\\n\"");
|
||||
do {
|
||||
sresult = Write(xfd->fd, "\r\n", 2);
|
||||
sresult = Write(wfd, "\r\n", 2);
|
||||
} while (sresult < 0 && errno == EINTR);
|
||||
/*! */
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xio-proxy.h,v 1.6 2006/05/31 19:17:57 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2002-2006 */
|
||||
/* $Id: xio-proxy.h,v 1.6.2.1 2006/07/24 19:18:10 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2002-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_proxy_h_included
|
||||
|
@ -19,7 +19,7 @@ extern const struct optdesc opt_ignorecr;
|
|||
extern const struct optdesc opt_proxy_resolve;
|
||||
extern const struct optdesc opt_proxy_authorization;
|
||||
|
||||
extern const struct addrdesc addr_proxy_connect;
|
||||
extern const union xioaddr_desc *xioaddrs_proxy_connect[];
|
||||
|
||||
int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts,
|
||||
const char *targetname, const char *targetport);
|
||||
|
|
33
xio-pty.c
33
xio-pty.c
|
@ -18,9 +18,18 @@
|
|||
|
||||
#define MAXPTYNAMELEN 64
|
||||
|
||||
static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
static int xioopen_pty(const char *linkname, struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups);
|
||||
static int xioopen_pty0(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
static int xioopen_pty1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
|
||||
const struct addrdesc addr_pty = { "pty", 3, xioopen_pty, GROUP_NAMED|GROUP_FD|GROUP_TERMIOS|GROUP_PTY, 0, 0, 0 HELP("") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_pty0 = { XIOADDR_SYS, "pty", 0, XIOBIT_ALL, GROUP_NAMED|GROUP_FD|GROUP_TERMIOS|GROUP_PTY, XIOSHUT_NONE, XIOCLOSE_CLOSE, xioopen_pty0, 0, 0, 0 HELP("") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_pty1 = { XIOADDR_SYS, "pty", 1, XIOBIT_ALL, GROUP_NAMED|GROUP_FD|GROUP_TERMIOS|GROUP_PTY, XIOSHUT_NONE, XIOCLOSE_CLOSE, xioopen_pty1, 0, 0, 0 HELP(":<symlink>") };
|
||||
|
||||
const union xioaddr_desc* xioaddrs_pty[] = {
|
||||
(union xioaddr_desc *)&xioendpoint_pty0,
|
||||
(union xioaddr_desc *)&xioendpoint_pty1,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct optdesc opt_symbolic_link = { "symbolic-link", "link", OPT_SYMBOLIC_LINK, GROUP_PTY, PH_LATE, TYPE_FILENAME, OFUNC_SPEC, 0, 0 };
|
||||
#if HAVE_POLL
|
||||
|
@ -28,7 +37,17 @@ const struct optdesc opt_pty_wait_slave = { "pty-wait-slave", "wait-slave", OPT_
|
|||
const struct optdesc opt_pty_intervall = { "pty-intervall", NULL, OPT_PTY_INTERVALL, GROUP_PTY, PH_EARLY, TYPE_TIMESPEC, OFUNC_SPEC, 0, 0 };
|
||||
#endif /* HAVE_POLL */
|
||||
|
||||
static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) {
|
||||
static int xioopen_pty0(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) {
|
||||
char *linkname = NULL;
|
||||
retropt_string(opts, OPT_SYMBOLIC_LINK, &linkname);
|
||||
return xioopen_pty(linkname, opts, xioflags, xfd, groups);
|
||||
}
|
||||
|
||||
static int xioopen_pty1(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) {
|
||||
return xioopen_pty(argv[1], opts, xioflags, xfd, groups);
|
||||
}
|
||||
|
||||
static int xioopen_pty(const char *linkname, struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups) {
|
||||
/* we expect the form: filename */
|
||||
int ptyfd = -1, ttyfd = -1;
|
||||
#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
|
||||
|
@ -39,7 +58,6 @@ static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xiofl
|
|||
#endif /* HAVE_OPENPTY */
|
||||
char ptyname[MAXPTYNAMELEN];
|
||||
char *tn = NULL;
|
||||
char *linkname = NULL;
|
||||
bool opt_unlink_close = true; /* remove symlink afterwards */
|
||||
bool wait_slave = false; /* true would be better for many platforms, but
|
||||
some OSes cannot handle this, and for common
|
||||
|
@ -47,8 +65,6 @@ static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xiofl
|
|||
compatibility we choose "no" as default */
|
||||
struct timespec pollintv = { PTY_INTERVALL };
|
||||
|
||||
xfd->stream.howtoend = END_CLOSE;
|
||||
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1;
|
||||
|
||||
|
@ -142,7 +158,7 @@ static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xiofl
|
|||
}
|
||||
#endif /* HAVE_OPENPTY */
|
||||
|
||||
if (!retropt_string(opts, OPT_SYMBOLIC_LINK, &linkname)) {
|
||||
if (linkname) {
|
||||
if (Unlink(linkname) < 0 && errno != ENOENT) {
|
||||
Error2("unlink(\"%s\"): %s", linkname, strerror(errno));
|
||||
}
|
||||
|
@ -163,10 +179,11 @@ static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xiofl
|
|||
|
||||
applyopts_cloexec(ptyfd, opts);/*!*/
|
||||
xfd->stream.dtype = XIODATA_PTY;
|
||||
xfd->stream.fdtype = FDTYPE_SINGLE;
|
||||
|
||||
applyopts(ptyfd, opts, PH_FD);
|
||||
|
||||
xfd->stream.fd = ptyfd;
|
||||
xfd->stream.fd1 = ptyfd;
|
||||
applyopts(ptyfd, opts, PH_LATE);
|
||||
if (applyopts_single(&xfd->stream, opts, PH_LATE) < 0) return -1;
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/* $Id: xio-pty.h,v 1.2 2004/10/24 13:49:53 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2002-2004 */
|
||||
/* $Id: xio-pty.h,v 1.2.2.1 2006/07/24 19:18:15 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2002-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_pty_h_included
|
||||
#define __xio_pty_h_included 1
|
||||
|
||||
extern const struct addrdesc addr_pty;
|
||||
extern const union xioaddr_desc* xioaddrs_pty[];
|
||||
|
||||
extern const struct optdesc opt_symbolic_link;
|
||||
#if HAVE_POLL
|
||||
|
|
49
xio-rawip.c
49
xio-rawip.c
|
@ -34,31 +34,41 @@ static
|
|||
int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xfd, unsigned groups,
|
||||
int pf, int socktype, int ipproto);
|
||||
|
||||
static
|
||||
int _xioopen_rawip_sendto(const char *hostname, const char *protname,
|
||||
struct opt *opts, int xioflags,
|
||||
xiofile_t *xxfd, unsigned groups, int pf);
|
||||
|
||||
const struct addrdesc addr_rawip_sendto = { "ip-sendto", 3, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") };
|
||||
const struct addrdesc addr_rawip_datagram= { "ip-datagram", 3, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") };
|
||||
const struct addrdesc addr_rawip_recvfrom= { "ip-recvfrom", 3, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") };
|
||||
const struct addrdesc addr_rawip_recv = { "ip-recv", 1, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_rawip_sendto2 = { XIOADDR_SYS, "ip-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_sendto, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") };
|
||||
const union xioaddr_desc *xioaddrs_rawip_sendto[] = { (union xioaddr_desc *)&xioaddr_rawip_sendto2, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_rawip_datagram2= { XIOADDR_SYS, "ip-datagram", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_datagram, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") };
|
||||
const union xioaddr_desc *xioaddrs_rawip_datagram[] = { (union xioaddr_desc *)&xioaddr_rawip_datagram2, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_rawip_recvfrom1= { XIOADDR_SYS, "ip-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recvfrom, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") };
|
||||
const union xioaddr_desc *xioaddrs_rawip_recvfrom[] = { (union xioaddr_desc *)&xioaddr_rawip_recvfrom1, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_rawip_recv1 = { XIOADDR_SYS, "ip-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recv, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") };
|
||||
const union xioaddr_desc *xioaddrs_rawip_recv[] = { (union xioaddr_desc *)&xioaddr_rawip_recv1, NULL };
|
||||
|
||||
#if WITH_IP4
|
||||
const struct addrdesc addr_rawip4_sendto = { "ip4-sendto", 3, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4, PF_INET, 0, 0 HELP(":<host>:<protocol>") };
|
||||
const struct addrdesc addr_rawip4_datagram= { "ip4-datagram", 3, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, PF_INET, 0, 0 HELP(":<host>:<protocol>") };
|
||||
const struct addrdesc addr_rawip4_recvfrom= { "ip4-recvfrom", 3, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_CHILD|GROUP_RANGE, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") };
|
||||
const struct addrdesc addr_rawip4_recv = { "ip4-recv", 1, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") };
|
||||
#endif
|
||||
static const struct xioaddr_endpoint_desc xioaddr_rawip4_sendto2 = { XIOADDR_SYS, "ip4-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_sendto, PF_INET, 0, 0 HELP(":<host>:<protocol>") };
|
||||
const union xioaddr_desc *xioaddrs_rawip4_sendto[] = { (union xioaddr_desc *)&xioaddr_rawip4_sendto2, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_rawip4_datagram2= { XIOADDR_SYS, "ip4-datagram", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_datagram, PF_INET, 0, 0 HELP(":<host>:<protocol>") };
|
||||
const union xioaddr_desc *xioaddrs_rawip4_datagram[] = { (union xioaddr_desc *)&xioaddr_rawip4_datagram2, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_rawip4_recvfrom1= { XIOADDR_SYS, "ip4-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recvfrom, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") };
|
||||
const union xioaddr_desc *xioaddrs_rawip4_recvfrom[] = { (union xioaddr_desc *)&xioaddr_rawip4_recvfrom1, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_rawip4_recv1 = { XIOADDR_SYS, "ip4-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recv, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") };
|
||||
const union xioaddr_desc *xioaddrs_rawip4_recv[] = { (union xioaddr_desc *)&xioaddr_rawip4_recv1, NULL };
|
||||
#endif /* IWITH_IP4 */
|
||||
|
||||
#if WITH_IP6
|
||||
const struct addrdesc addr_rawip6_sendto = { "ip6-sendto", 3, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6, PF_INET6, 0, 0 HELP(":<host>:<protocol>") };
|
||||
const struct addrdesc addr_rawip6_datagram= { "ip6-datagram", 3, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, PF_INET6, 0, 0 HELP(":<host>:<protocol>") };
|
||||
const struct addrdesc addr_rawip6_recvfrom= { "ip6-recvfrom", 3, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") };
|
||||
const struct addrdesc addr_rawip6_recv = { "ip6-recv", 1, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") };
|
||||
#endif
|
||||
|
||||
static const struct xioaddr_endpoint_desc xioaddr_rawip6_sendto2 = { XIOADDR_SYS, "ip6-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_sendto, PF_INET6, 0, 0 HELP(":<host>:<protocol>") };
|
||||
const union xioaddr_desc *xioaddrs_rawip6_sendto[] = { (union xioaddr_desc *)&xioaddr_rawip6_sendto2, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_rawip6_datagram2= { XIOADDR_SYS, "ip6-datagram", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_datagram, PF_INET6, 0, 0 HELP(":<host>:<protocol>") };
|
||||
const union xioaddr_desc *xioaddrs_rawip6_datagram[] = { (union xioaddr_desc *)&xioaddr_rawip6_datagram2, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_rawip6_recvfrom1= { XIOADDR_SYS, "ip6-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recvfrom, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") };
|
||||
const union xioaddr_desc *xioaddrs_rawip6_recvfrom[] = { (union xioaddr_desc *)&xioaddr_rawip6_recvfrom1, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_rawip6_recv1 = { XIOADDR_SYS, "ip6-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recv, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") };
|
||||
const union xioaddr_desc *xioaddrs_rawip6_recv[] = { (union xioaddr_desc *)&xioaddr_rawip6_recv1, NULL };
|
||||
#endif /* WITH_IP6 */
|
||||
|
||||
/* we expect the form: host:protocol */
|
||||
/* struct sockaddr_in sa;*/
|
||||
|
@ -106,7 +116,6 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname,
|
|||
/*return STAT_NORETRY;*/
|
||||
}
|
||||
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
||||
|
||||
/* ...res_opts[] */
|
||||
|
@ -128,6 +137,7 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname,
|
|||
|
||||
uslen = socket_init(pf, &us);
|
||||
|
||||
xfd->fdtype = FDTYPE_SINGLE;
|
||||
xfd->dtype = XIODATA_RECVFROM_SKIPIP;
|
||||
|
||||
if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, feats,
|
||||
|
@ -215,7 +225,8 @@ int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts,
|
|||
protname);
|
||||
/*return STAT_NORETRY;*/
|
||||
}
|
||||
xfd->stream.howtoend = END_NONE;
|
||||
xfd->stream.howtoshut = XIOSHUT_NONE;
|
||||
xfd->stream.howtoclose = XIOCLOSE_CLOSE;
|
||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
||||
|
||||
retropt_socket_pf(opts, &pf);
|
||||
|
@ -235,6 +246,7 @@ int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts,
|
|||
needbind = true;
|
||||
}
|
||||
|
||||
xfd->stream.fdtype = FDTYPE_SINGLE;
|
||||
xfd->stream.dtype = XIODATA_RECVFROM_SKIPIP_ONE;
|
||||
if ((result =
|
||||
_xioopen_dgram_recvfrom(&xfd->stream, xioflags, needbind?&us.soa:NULL,
|
||||
|
@ -293,6 +305,7 @@ int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts,
|
|||
xfd->stream.para.socket.la.soa.sa_family = pf;
|
||||
}
|
||||
|
||||
xfd->stream.fdtype = FDTYPE_SINGLE;
|
||||
xfd->stream.dtype = XIODATA_RECV_SKIPIP;
|
||||
result = _xioopen_dgram_recv(&xfd->stream, xioflags, NULL/*&us.soa*/, uslen,
|
||||
opts, pf, socktype, ipproto, E_ERROR);
|
||||
|
|
24
xio-rawip.h
24
xio-rawip.h
|
@ -5,17 +5,17 @@
|
|||
#ifndef __xio_rawip_h_included
|
||||
#define __xio_rawip_h_included 1
|
||||
|
||||
extern const struct addrdesc addr_rawip_sendto;
|
||||
extern const struct addrdesc addr_rawip_datagram;
|
||||
extern const struct addrdesc addr_rawip_recvfrom;
|
||||
extern const struct addrdesc addr_rawip_recv;
|
||||
extern const struct addrdesc addr_rawip4_sendto;
|
||||
extern const struct addrdesc addr_rawip4_datagram;
|
||||
extern const struct addrdesc addr_rawip4_recvfrom;
|
||||
extern const struct addrdesc addr_rawip4_recv;
|
||||
extern const struct addrdesc addr_rawip6_sendto;
|
||||
extern const struct addrdesc addr_rawip6_datagram;
|
||||
extern const struct addrdesc addr_rawip6_recvfrom;
|
||||
extern const struct addrdesc addr_rawip6_recv;
|
||||
extern const union xioaddr_desc *xioaddrs_rawip_sendto[];
|
||||
extern const union xioaddr_desc *xioaddrs_rawip_datagram[];
|
||||
extern const union xioaddr_desc *xioaddrs_rawip_recvfrom[];
|
||||
extern const union xioaddr_desc *xioaddrs_rawip_recv[];
|
||||
extern const union xioaddr_desc *xioaddrs_rawip4_sendto[];
|
||||
extern const union xioaddr_desc *xioaddrs_rawip4_datagram[];
|
||||
extern const union xioaddr_desc *xioaddrs_rawip4_recvfrom[];
|
||||
extern const union xioaddr_desc *xioaddrs_rawip4_recv[];
|
||||
extern const union xioaddr_desc *xioaddrs_rawip6_sendto[];
|
||||
extern const union xioaddr_desc *xioaddrs_rawip6_datagram[];
|
||||
extern const union xioaddr_desc *xioaddrs_rawip6_recvfrom[];
|
||||
extern const union xioaddr_desc *xioaddrs_rawip6_recv[];
|
||||
|
||||
#endif /* !defined(__xio_rawip_h_included) */
|
||||
|
|
|
@ -30,8 +30,13 @@ static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
|
|||
int dummy1, int dummy2, int dummy3);
|
||||
|
||||
|
||||
const struct addrdesc addr_readline = {
|
||||
"readline", 3, xioopen_readline, GROUP_FD|GROUP_TERMIOS|GROUP_READLINE, 0, 0, 0 HELP(NULL) };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_readline0 = {
|
||||
XIOADDR_SYS, "readline", 0, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_TERMIOS|GROUP_READLINE, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_readline, 0, 0, 0 HELP(NULL) };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_readline[] = {
|
||||
(union xioaddr_desc *)&xioendpoint_readline0,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct optdesc opt_history_file = { "history-file", "history", OPT_HISTORY_FILE, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.readline.history_file };
|
||||
const struct optdesc opt_prompt = { "prompt", NULL, OPT_PROMPT, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.readline.prompt };
|
||||
|
@ -69,15 +74,16 @@ static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
|
|||
}
|
||||
Notice(msgbuf);
|
||||
|
||||
xfd->stream.fd = 0; /* stdin */
|
||||
xfd->stream.howtoend = END_NONE;
|
||||
xfd->stream.fd1 = 0; /* stdin */
|
||||
xfd->stream.howtoclose = XIOCLOSE_READLINE;
|
||||
xfd->stream.dtype = XIODATA_READLINE;
|
||||
xfd->stream.fdtype = FDTYPE_SINGLE;
|
||||
|
||||
#if WITH_TERMIOS
|
||||
if (Isatty(xfd->stream.fd)) {
|
||||
if (Tcgetattr(xfd->stream.fd, &xfd->stream.savetty) < 0) {
|
||||
if (Isatty(xfd->stream.fd1)) {
|
||||
if (Tcgetattr(xfd->stream.fd1, &xfd->stream.savetty) < 0) {
|
||||
Warn2("cannot query current terminal settings on fd %d. %s",
|
||||
xfd->stream.fd, strerror(errno));
|
||||
xfd->stream.fd1, strerror(errno));
|
||||
} else {
|
||||
xfd->stream.ttyvalid = true;
|
||||
}
|
||||
|
@ -87,7 +93,7 @@ static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
|
|||
if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
applyopts2(xfd->stream.fd, opts, PH_INIT, PH_FD);
|
||||
applyopts2(xfd->stream.fd1, opts, PH_INIT, PH_FD);
|
||||
|
||||
Using_history();
|
||||
applyopts_offset(&xfd->stream, opts);
|
||||
|
@ -120,8 +126,8 @@ static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
|
|||
if (xfd->stream.para.readline.history_file) {
|
||||
Read_history(xfd->stream.para.readline.history_file);
|
||||
}
|
||||
xiotermios_clrflag(xfd->stream.fd, 3, ICANON);
|
||||
xiotermios_clrflag(xfd->stream.fd, 3, ECHO);
|
||||
xiotermios_clrflag(xfd->stream.fd1, 3, ICANON);
|
||||
xiotermios_clrflag(xfd->stream.fd1, 3, ECHO);
|
||||
return _xio_openlate(&xfd->stream, opts);
|
||||
}
|
||||
|
||||
|
@ -141,40 +147,40 @@ ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) {
|
|||
readline */
|
||||
struct termios saveterm, setterm;
|
||||
*pipe->para.readline.dynend = '\0';
|
||||
Tcgetattr(pipe->fd, &saveterm); /*! error */
|
||||
Tcgetattr(pipe->fd1, &saveterm); /*! error */
|
||||
setterm = saveterm;
|
||||
setterm.c_lflag |= ICANON;
|
||||
Tcsetattr(pipe->fd, TCSANOW, &setterm); /*!*/
|
||||
Tcsetattr(pipe->fd1, TCSANOW, &setterm); /*!*/
|
||||
do {
|
||||
bytes = Read(pipe->fd, buff, bufsiz);
|
||||
bytes = Read(pipe->fd1, buff, bufsiz);
|
||||
} while (bytes < 0 && errno == EINTR);
|
||||
if (bytes < 0) {
|
||||
_errno = errno;
|
||||
Error4("read(%d, %p, "F_Zu"): %s",
|
||||
pipe->fd, buff, bufsiz, strerror(_errno));
|
||||
pipe->fd1, buff, bufsiz, strerror(_errno));
|
||||
errno = _errno;
|
||||
return -1;
|
||||
}
|
||||
setterm.c_lflag &= ~ICANON;
|
||||
Tcgetattr(pipe->fd, &setterm); /*! error */
|
||||
Tcsetattr(pipe->fd, TCSANOW, &saveterm); /*!*/
|
||||
Tcgetattr(pipe->fd1, &setterm); /*! error */
|
||||
Tcsetattr(pipe->fd1, TCSANOW, &saveterm); /*!*/
|
||||
pipe->para.readline.dynend = pipe->para.readline.dynprompt;
|
||||
/*Write(pipe->fd, "\n", 1);*/ /*!*/
|
||||
/*Write(pipe->fd1, "\n", 1);*/ /*!*/
|
||||
return bytes;
|
||||
}
|
||||
#endif /* HAVE_REGEX_H */
|
||||
|
||||
xiotermios_setflag(pipe->fd, 3, ECHO);
|
||||
xiotermios_setflag(pipe->fd1, 3, ECHO);
|
||||
if (pipe->para.readline.prompt || pipe->para.readline.dynprompt) {
|
||||
/* we must carriage return, because readline will first print the
|
||||
prompt */
|
||||
ssize_t writt;
|
||||
do {
|
||||
writt = Write(pipe->fd, "\r", 1);
|
||||
writt = Write(pipe->fd1, "\r", 1);
|
||||
} while (writt < 0 && errno == EINTR);
|
||||
if (writt < 0) {
|
||||
Warn2("write(%d, \"\\r\", 1): %s",
|
||||
pipe->fd, strerror(errno));
|
||||
pipe->fd1, strerror(errno));
|
||||
} else if (writt < 1) {
|
||||
Warn1("write() only wrote "F_Zu" of 1 byte", writt);
|
||||
}
|
||||
|
@ -191,7 +197,7 @@ ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) {
|
|||
if (line == NULL) {
|
||||
return 0; /* EOF */
|
||||
}
|
||||
xiotermios_clrflag(pipe->fd, 3, ECHO);
|
||||
xiotermios_clrflag(pipe->fd1, 3, ECHO);
|
||||
Add_history(line);
|
||||
bytes = strlen(line);
|
||||
strncpy(buff, line, bufsiz);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/* $Id: xio-readline.h,v 1.4 2003/12/23 21:38:59 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2002, 2003 */
|
||||
/* $Id: xio-readline.h,v 1.4.2.1 2006/07/24 19:18:24 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2002-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_readline_h_included
|
||||
#define __xio_readline_h_included 1
|
||||
|
||||
extern const struct addrdesc addr_readline;
|
||||
extern const union xioaddr_desc *xioaddrs_readline[];
|
||||
|
||||
extern const struct optdesc opt_history_file;
|
||||
extern const struct optdesc opt_prompt;
|
||||
|
|
167
xio-socket.c
167
xio-socket.c
|
@ -9,6 +9,7 @@
|
|||
#if _WITH_SOCKET
|
||||
|
||||
#include "xioopen.h"
|
||||
#include "xiosigchld.h"
|
||||
#include "xio-socket.h"
|
||||
#include "xio-named.h"
|
||||
#if WITH_IP4
|
||||
|
@ -144,20 +145,21 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
|||
int _errno;
|
||||
int result;
|
||||
|
||||
if ((xfd->fd = Socket(pf, stype, proto)) < 0) {
|
||||
if ((xfd->fd1 = Socket(pf, stype, proto)) < 0) {
|
||||
Msg4(level,
|
||||
"socket(%d, %d, %d): %s", pf, stype, proto, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
xfd->fdtype = FDTYPE_SINGLE;
|
||||
|
||||
applyopts_offset(xfd, opts);
|
||||
applyopts(xfd->fd, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->fd, opts, PH_FD);
|
||||
applyopts(xfd->fd1, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->fd1, opts, PH_FD);
|
||||
|
||||
applyopts_cloexec(xfd->fd, opts);
|
||||
applyopts_cloexec(xfd->fd1, opts);
|
||||
|
||||
applyopts(xfd->fd, opts, PH_PREBIND);
|
||||
applyopts(xfd->fd, opts, PH_BIND);
|
||||
applyopts(xfd->fd1, opts, PH_PREBIND);
|
||||
applyopts(xfd->fd1, opts, PH_BIND);
|
||||
#if WITH_TCP || WITH_UDP
|
||||
if (alt) {
|
||||
union sockaddr_union sin, *sinp;
|
||||
|
@ -214,13 +216,13 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
|||
problem = false;
|
||||
do { /* loop over lowport bind() attempts */
|
||||
*port = htons(i);
|
||||
if (Bind(xfd->fd, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) {
|
||||
if (Bind(xfd->fd1, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) {
|
||||
Msg4(errno==EADDRINUSE?E_INFO:level,
|
||||
"bind(%d, {%s}, "F_Zd"): %s", xfd->fd,
|
||||
"bind(%d, {%s}, "F_Zd"): %s", xfd->fd1,
|
||||
sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
|
||||
sizeof(*sinp), strerror(errno));
|
||||
if (errno != EADDRINUSE) {
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} else {
|
||||
|
@ -230,7 +232,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
|||
if (i == N) {
|
||||
Msg(level, "no low port available");
|
||||
/*errno = EADDRINUSE; still assigned */
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} while (i != N);
|
||||
|
@ -238,31 +240,31 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
|||
#endif /* WITH_TCP || WITH_UDP */
|
||||
|
||||
if (us) {
|
||||
if (Bind(xfd->fd, us, uslen) < 0) {
|
||||
if (Bind(xfd->fd1, us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
||||
xfd->fd, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)),
|
||||
xfd->fd1, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)),
|
||||
uslen, strerror(errno));
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
|
||||
applyopts(xfd->fd, opts, PH_PASTBIND);
|
||||
applyopts(xfd->fd1, opts, PH_PASTBIND);
|
||||
|
||||
applyopts(xfd->fd, opts, PH_CONNECT);
|
||||
applyopts(xfd->fd1, opts, PH_CONNECT);
|
||||
|
||||
if (xfd->para.socket.connect_timeout.tv_sec != 0 ||
|
||||
xfd->para.socket.connect_timeout.tv_usec != 0) {
|
||||
fcntl_flags = Fcntl(xfd->fd, F_GETFL);
|
||||
Fcntl_l(xfd->fd, F_SETFL, fcntl_flags|O_NONBLOCK);
|
||||
fcntl_flags = Fcntl(xfd->fd1, F_GETFL);
|
||||
Fcntl_l(xfd->fd1, F_SETFL, fcntl_flags|O_NONBLOCK);
|
||||
}
|
||||
|
||||
result = Connect(xfd->fd, (struct sockaddr *)them, themlen);
|
||||
result = Connect(xfd->fd1, (struct sockaddr *)them, themlen);
|
||||
_errno = errno;
|
||||
la.soa.sa_family = them->sa_family; lalen = sizeof(la);
|
||||
if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) {
|
||||
if (Getsockname(xfd->fd1, &la.soa, &lalen) < 0) {
|
||||
Msg4(level-1, "getsockname(%d, %p, {%d}): %s",
|
||||
xfd->fd, &la.soa, lalen, strerror(errno));
|
||||
xfd->fd1, &la.soa, lalen, strerror(errno));
|
||||
}
|
||||
errno = _errno;
|
||||
if (result < 0) {
|
||||
|
@ -273,15 +275,15 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
|||
fd_set readfds, writefds, exceptfds;
|
||||
int result;
|
||||
Info4("connect(%d, %s, "F_Zd"): %s",
|
||||
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||
xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||
themlen, strerror(errno));
|
||||
timeout = xfd->para.socket.connect_timeout;
|
||||
FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
|
||||
FD_SET(xfd->fd, &readfds); FD_SET(xfd->fd, &writefds);
|
||||
FD_SET(xfd->fd1, &readfds); FD_SET(xfd->fd1, &writefds);
|
||||
result =
|
||||
Select(xfd->fd+1, &readfds, &writefds, &exceptfds, &timeout);
|
||||
Select(xfd->fd1+1, &readfds, &writefds, &exceptfds, &timeout);
|
||||
if (result < 0) {
|
||||
Msg2(level, "select(%d,,,,): %s", xfd->fd+1, strerror(errno));
|
||||
Msg2(level, "select(%d,,,,): %s", xfd->fd1+1, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
if (result == 0) {
|
||||
|
@ -290,26 +292,26 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
|||
strerror(ETIMEDOUT));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
if (FD_ISSET(xfd->fd, &readfds)) {
|
||||
if (FD_ISSET(xfd->fd1, &readfds)) {
|
||||
#if 0
|
||||
unsigned char dummy[1];
|
||||
Read(xfd->fd, &dummy, 1); /* get error message */
|
||||
Read(xfd->fd1, &dummy, 1); /* get error message */
|
||||
Msg2(level, "connecting to %s: %s",
|
||||
sockaddr_info(them, infobuff, sizeof(infobuff)),
|
||||
strerror(errno));
|
||||
#else
|
||||
Connect(xfd->fd, them, themlen); /* get error message */
|
||||
Connect(xfd->fd1, them, themlen); /* get error message */
|
||||
Msg4(level, "connect(%d, %s, "F_Zd"): %s",
|
||||
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||
xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||
themlen, strerror(errno));
|
||||
#endif
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
/* otherwise OK */
|
||||
Fcntl_l(xfd->fd, F_SETFL, fcntl_flags);
|
||||
Fcntl_l(xfd->fd1, F_SETFL, fcntl_flags);
|
||||
} else {
|
||||
Warn4("connect(%d, %s, "F_Zd"): %s",
|
||||
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||
xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||
themlen, strerror(errno));
|
||||
}
|
||||
} else if (pf == PF_UNIX && errno == EPROTOTYPE) {
|
||||
|
@ -317,7 +319,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
|||
the only way to distinguish stream and datagram sockets */
|
||||
int _errno = errno;
|
||||
Info4("connect(%d, %s, "F_Zd"): %s",
|
||||
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||
xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||
themlen, strerror(errno));
|
||||
#if 0
|
||||
Info("assuming datagram socket");
|
||||
|
@ -326,22 +328,21 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
|||
memcpy(&xfd->peersa.soa, them, xfd->salen);
|
||||
#endif
|
||||
/*!!! and remove bind socket */
|
||||
Close(xfd->fd); xfd->fd = -1;
|
||||
Close(xfd->fd1); xfd->fd1 = -1;
|
||||
errno = _errno;
|
||||
return -1;
|
||||
} else {
|
||||
Msg4(level, "connect(%d, %s, "F_Zd"): %s",
|
||||
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||
xfd->fd1, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||
themlen, strerror(errno));
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
|
||||
applyopts_fchown(xfd->fd, opts);
|
||||
applyopts(xfd->fd, opts, PH_CONNECTED);
|
||||
applyopts(xfd->fd, opts, PH_LATE);
|
||||
|
||||
applyopts_fchown(xfd->fd1, opts);
|
||||
applyopts(xfd->fd1, opts, PH_CONNECTED);
|
||||
applyopts(xfd->fd1, opts, PH_LATE);
|
||||
Notice1("successfully connected from local address %s",
|
||||
sockaddr_info(&la.soa, themlen, infobuff, sizeof(infobuff)));
|
||||
|
||||
|
@ -428,7 +429,7 @@ int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
|||
}
|
||||
/* parent process */
|
||||
Notice1("forked off child process "F_pid, pid);
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
/* with and without retry */
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
|
@ -458,7 +459,7 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
|
|||
union sockaddr_union la; socklen_t lalen = sizeof(la);
|
||||
char infobuff[256];
|
||||
|
||||
if ((xfd->fd = Socket(pf, socktype, ipproto)) < 0) {
|
||||
if ((xfd->fd1 = Socket(pf, socktype, ipproto)) < 0) {
|
||||
Msg4(level,
|
||||
"socket(%d, %d, %d): %s", pf, socktype, ipproto, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
|
@ -466,36 +467,36 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
|
|||
|
||||
applyopts_offset(xfd, opts);
|
||||
applyopts_single(xfd, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->fd, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->fd, opts, PH_FD);
|
||||
applyopts(xfd->fd1, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->fd1, opts, PH_FD);
|
||||
|
||||
applyopts_cloexec(xfd->fd, opts);
|
||||
applyopts_cloexec(xfd->fd1, opts);
|
||||
|
||||
applyopts(xfd->fd, opts, PH_PREBIND);
|
||||
applyopts(xfd->fd, opts, PH_BIND);
|
||||
applyopts(xfd->fd1, opts, PH_PREBIND);
|
||||
applyopts(xfd->fd1, opts, PH_BIND);
|
||||
|
||||
if (us) {
|
||||
if (Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) {
|
||||
if (Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
||||
xfd->fd, sockaddr_info((struct sockaddr *)us, uslen, infobuff, sizeof(infobuff)),
|
||||
xfd->fd1, sockaddr_info((struct sockaddr *)us, uslen, infobuff, sizeof(infobuff)),
|
||||
uslen, strerror(errno));
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
|
||||
applyopts(xfd->fd, opts, PH_PASTBIND);
|
||||
applyopts(xfd->fd1, opts, PH_PASTBIND);
|
||||
|
||||
/*applyopts(xfd->fd, opts, PH_CONNECT);*/
|
||||
/*applyopts(xfd->fd1, opts, PH_CONNECT);*/
|
||||
|
||||
if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) {
|
||||
if (Getsockname(xfd->fd1, &la.soa, &lalen) < 0) {
|
||||
Warn4("getsockname(%d, %p, {%d}): %s",
|
||||
xfd->fd, &la.soa, lalen, strerror(errno));
|
||||
xfd->fd1, &la.soa, lalen, strerror(errno));
|
||||
}
|
||||
|
||||
applyopts_fchown(xfd->fd, opts);
|
||||
applyopts(xfd->fd, opts, PH_CONNECTED);
|
||||
applyopts(xfd->fd, opts, PH_LATE);
|
||||
applyopts_fchown(xfd->fd1, opts);
|
||||
applyopts(xfd->fd1, opts, PH_CONNECTED);
|
||||
applyopts(xfd->fd1, opts, PH_LATE);
|
||||
|
||||
/* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */
|
||||
Notice1("successfully prepared local socket %s",
|
||||
|
@ -577,24 +578,24 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
|||
}
|
||||
#endif /* 1 */
|
||||
|
||||
if ((xfd->fd = Socket(pf, socktype, proto)) < 0) {
|
||||
if ((xfd->fd1 = Socket(pf, socktype, proto)) < 0) {
|
||||
Msg4(level,
|
||||
"socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
applyopts_single(xfd, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->fd, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->fd1, opts, PH_PASTSOCKET);
|
||||
|
||||
applyopts_cloexec(xfd->fd, opts);
|
||||
applyopts_cloexec(xfd->fd1, opts);
|
||||
|
||||
applyopts(xfd->fd, opts, PH_PREBIND);
|
||||
applyopts(xfd->fd, opts, PH_BIND);
|
||||
if ((us != NULL) && Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd,
|
||||
applyopts(xfd->fd1, opts, PH_PREBIND);
|
||||
applyopts(xfd->fd1, opts, PH_BIND);
|
||||
if ((us != NULL) && Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1,
|
||||
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
|
||||
strerror(errno));
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
|
@ -604,7 +605,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
|||
}
|
||||
#endif
|
||||
|
||||
applyopts(xfd->fd, opts, PH_PASTBIND);
|
||||
applyopts(xfd->fd1, opts, PH_PASTBIND);
|
||||
#if WITH_UNIX
|
||||
if (pf == AF_UNIX && us != NULL) {
|
||||
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
|
||||
|
@ -688,7 +689,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
|||
if (drop) {
|
||||
char *dummy[2];
|
||||
|
||||
Recv(xfd->fd, dummy, sizeof(dummy), 0);
|
||||
Recv(xfd->fd1, dummy, sizeof(dummy), 0);
|
||||
drop = true;
|
||||
}
|
||||
|
||||
|
@ -702,8 +703,8 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
|||
Notice1("receiving IP protocol %u", proto);
|
||||
}
|
||||
FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt);
|
||||
FD_SET(xfd->fd, &in);
|
||||
if (Select(xfd->fd+1, &in, &out, &expt, NULL) > 0) {
|
||||
FD_SET(xfd->fd1, &in);
|
||||
if (Select(xfd->fd1+1, &in, &out, &expt, NULL) > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -711,12 +712,12 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
|||
continue;
|
||||
}
|
||||
|
||||
Msg2(level, "select(, {%d}): %s", xfd->fd, strerror(errno));
|
||||
Close(xfd->fd);
|
||||
Msg2(level, "select(, {%d}): %s", xfd->fd1, strerror(errno));
|
||||
Close(xfd->fd1);
|
||||
return STAT_RETRYLATER;
|
||||
} while (true);
|
||||
|
||||
if (xiogetpacketsrc(xfd->fd, pa, &palen) < 0) {
|
||||
if (xiogetpacketsrc(xfd->fd1, pa, &palen) < 0) {
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
|
@ -727,16 +728,16 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
|||
if (xiocheckpeer(xfd, pa, la) < 0) {
|
||||
/* drop packet */
|
||||
char buff[512];
|
||||
Recv(xfd->fd, buff, sizeof(buff), 0);
|
||||
Recv(xfd->fd1, buff, sizeof(buff), 0);
|
||||
continue;
|
||||
}
|
||||
Info1("permitting packet from %s",
|
||||
sockaddr_info((struct sockaddr *)pa, palen,
|
||||
infobuff, sizeof(infobuff)));
|
||||
|
||||
applyopts(xfd->fd, opts, PH_FD);
|
||||
applyopts(xfd->fd1, opts, PH_FD);
|
||||
|
||||
applyopts(xfd->fd, opts, PH_CONNECTED);
|
||||
applyopts(xfd->fd1, opts, PH_CONNECTED);
|
||||
|
||||
xfd->peersa = *(union sockaddr_union *)pa;
|
||||
xfd->salen = palen;
|
||||
|
@ -758,7 +759,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
|||
|
||||
if ((pid = Fork()) < 0) {
|
||||
Msg1(level, "fork(): %s", strerror(errno));
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
@ -830,24 +831,24 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
|
|||
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
|
||||
|
||||
if ((xfd->fd = Socket(pf, socktype, proto)) < 0) {
|
||||
if ((xfd->fd1 = Socket(pf, socktype, proto)) < 0) {
|
||||
Msg4(level,
|
||||
"socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
applyopts_single(xfd, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->fd, opts, PH_PASTSOCKET);
|
||||
applyopts(xfd->fd1, opts, PH_PASTSOCKET);
|
||||
|
||||
applyopts_cloexec(xfd->fd, opts);
|
||||
applyopts_cloexec(xfd->fd1, opts);
|
||||
|
||||
applyopts(xfd->fd, opts, PH_PREBIND);
|
||||
applyopts(xfd->fd, opts, PH_BIND);
|
||||
if ((us != NULL) && Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd,
|
||||
applyopts(xfd->fd1, opts, PH_PREBIND);
|
||||
applyopts(xfd->fd1, opts, PH_BIND);
|
||||
if ((us != NULL) && Bind(xfd->fd1, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd1,
|
||||
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
|
||||
strerror(errno));
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
|
@ -857,7 +858,7 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
|
|||
}
|
||||
#endif
|
||||
|
||||
applyopts(xfd->fd, opts, PH_PASTBIND);
|
||||
applyopts(xfd->fd1, opts, PH_PASTBIND);
|
||||
#if WITH_UNIX
|
||||
if (pf == AF_UNIX && us != NULL) {
|
||||
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xio-socket.h,v 1.16 2006/12/30 23:04:21 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_socket_h_included
|
||||
|
|
110
xio-socks.c
110
xio-socks.c
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xio-socks.c,v 1.33 2006/12/28 14:06:37 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for opening addresses of socks4 type */
|
||||
|
@ -35,10 +35,25 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
|||
const struct optdesc opt_socksport = { "socksport", NULL, OPT_SOCKSPORT, GROUP_IP_SOCKS4, PH_LATE, TYPE_STRING, OFUNC_SPEC };
|
||||
const struct optdesc opt_socksuser = { "socksuser", NULL, OPT_SOCKSUSER, GROUP_IP_SOCKS4, PH_LATE, TYPE_NAME, OFUNC_SPEC };
|
||||
|
||||
const struct addrdesc addr_socks4_connect = { "socks4", 3, xioopen_socks4_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<socks-server>:<host>:<port>") };
|
||||
static const struct xioaddr_inter_desc xiointer_socks4_connect2 = { XIOADDR_INTER, "socks4", 2, XIOBIT_ALL, GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socks4_connect, 0, 0, 0, XIOBIT_RDWR HELP(":<host>:<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_socks4_connect3 = { XIOADDR_ENDPOINT, "socks4", 3, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socks4_connect, 0, 0, 0 HELP(":<socks-server>:<host>:<port>") };
|
||||
|
||||
const struct addrdesc addr_socks4a_connect = { "socks4a", 3, xioopen_socks4_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, 1, 0, 0 HELP(":<socks-server>:<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_socks4_connect[] = {
|
||||
(union xioaddr_desc *)&xiointer_socks4_connect2,
|
||||
(union xioaddr_desc *)&xioendpoint_socks4_connect3,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct xioaddr_inter_desc xiointer_socks4a_connect2 = { XIOADDR_INTER, "socks4a", 2, XIOBIT_ALL, GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socks4_connect, 1, 0, 0, XIOBIT_RDWR HELP(":<host>:<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_socks4a_connect3 = { XIOADDR_ENDPOINT, "socks4a", 3, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socks4_connect, 1, 0, 0 HELP(":<socks-server>:<host>:<port>") };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_socks4a_connect[] = {
|
||||
(union xioaddr_desc *)&xiointer_socks4a_connect2,
|
||||
(union xioaddr_desc *)&xioendpoint_socks4a_connect3,
|
||||
NULL
|
||||
};
|
||||
|
||||
/*!!! should be two different functions */
|
||||
static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups, int socks4a, int dummy2,
|
||||
|
@ -46,7 +61,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
|||
/* we expect the form: host:host:port */
|
||||
struct single *xfd = &xxfd->stream;
|
||||
struct opt *opts0 = NULL;
|
||||
const char *sockdname; char *socksport;
|
||||
const char *sockdname; char *sockdport;
|
||||
const char *targetname, *targetport;
|
||||
int pf = PF_UNSPEC;
|
||||
int ipproto = IPPROTO_TCP;
|
||||
|
@ -58,21 +73,36 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
|||
bool needbind = false;
|
||||
bool lowport = false;
|
||||
unsigned char buff[BUFF_LEN];
|
||||
struct socks4 *sockhead = (struct socks4 *)buff;
|
||||
struct socks4request *sockhead = (struct socks4request *)buff;
|
||||
size_t buflen = sizeof(buff);
|
||||
int socktype = SOCK_STREAM;
|
||||
int level;
|
||||
int result;
|
||||
|
||||
if (argc != 4) {
|
||||
Error1("%s: 3 parameters required", argv[0]);
|
||||
if (argc < 3 || argc > 4) {
|
||||
Warn("syntax 1 (terminal): socks-connect:<socks-server>:<host>:<port>");
|
||||
Error("syntax 2 (inter): socks-connect:<host>:<port>");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
if (argc == 3) {
|
||||
if (xfd->fd1 < 0) {
|
||||
Error("xioopen_socks4_connect(): socksservername missing");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
sockdname = NULL;
|
||||
targetname = argv[1];
|
||||
targetport = argv[2];
|
||||
} else /* if (argc == 4) */ {
|
||||
if (xfd->fd1 >= 0) {
|
||||
Error("xioopen_socks4_connect(): socksservername not allowed here");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
sockdname = argv[1];
|
||||
targetname = argv[2];
|
||||
targetport = argv[3];
|
||||
}
|
||||
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
|
@ -80,20 +110,26 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
|||
|
||||
retropt_bool(opts, OPT_FORK, &dofork);
|
||||
|
||||
result = _xioopen_socks4_prepare(targetport, opts, &socksport, sockhead, &buflen);
|
||||
result = _xioopen_socks4_prepare(targetport, opts, &sockdport, sockhead, &buflen);
|
||||
if (result != STAT_OK) return result;
|
||||
if (xfd->fd2 < 0) {
|
||||
result =
|
||||
_xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport,
|
||||
_xioopen_ipapp_prepare(opts, &opts0, sockdname, sockdport,
|
||||
&pf, ipproto,
|
||||
xfd->para.socket.ip.res_opts[1],
|
||||
xfd->para.socket.ip.res_opts[0],
|
||||
them, &themlen, us, &uslen,
|
||||
&needbind, &lowport, &socktype);
|
||||
if (result != STAT_OK) return result;
|
||||
|
||||
Notice5("opening connection to %s:%u via socks4 server %s:%s as user \"%s\"",
|
||||
targetname,
|
||||
ntohs(sockhead->port),
|
||||
sockdname, socksport, sockhead->userid);
|
||||
sockdname, sockdport, sockhead->userid);
|
||||
} else {
|
||||
Notice3("opening connection to %s:%u using socks4 connect as user \"%s\"",
|
||||
targetname, ntohs(sockhead->port), sockhead->userid);
|
||||
}
|
||||
|
||||
do { /* loop over failed connect and socks-request attempts */
|
||||
|
||||
|
@ -123,6 +159,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
|||
return result;
|
||||
}
|
||||
|
||||
if (xfd->fd2 < 0) {
|
||||
/* this cannot fork because we retrieved fork option above */
|
||||
result =
|
||||
_xioopen_connect (xfd,
|
||||
|
@ -142,8 +179,14 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
|||
default:
|
||||
return result;
|
||||
}
|
||||
xfd->fdtype = FDTYPE_SINGLE;
|
||||
} else {
|
||||
xfd->dtype = XIODATA_STREAM;
|
||||
xfd->fdtype = FDTYPE_DOUBLE;
|
||||
}
|
||||
|
||||
applyopts(xfd->fd, opts, PH_ALL);
|
||||
/*!*/
|
||||
applyopts(xfd->fd1, opts, PH_ALL);
|
||||
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
return result;
|
||||
|
@ -190,7 +233,8 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
|||
}
|
||||
/* parent process */
|
||||
Notice1("forked off child process "F_pid, pid);
|
||||
Close(xfd->fd);
|
||||
Close(xfd->fd1);
|
||||
Close(xfd->fd2);
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
continue;
|
||||
|
@ -205,7 +249,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
|||
}
|
||||
|
||||
|
||||
int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **socksport, struct socks4 *sockhead, size_t *headlen) {
|
||||
int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **socksport, struct socks4request *sockhead, size_t *headlen) {
|
||||
struct servent *se;
|
||||
char *userid;
|
||||
|
||||
|
@ -247,7 +291,7 @@ int
|
|||
_xioopen_socks4_connect0(struct single *xfd,
|
||||
const char *hostname, /* socks target host */
|
||||
int socks4a,
|
||||
struct socks4 *sockhead,
|
||||
struct socks4request *sockhead,
|
||||
ssize_t *headlen, /* get available space,
|
||||
return used length*/
|
||||
int level) {
|
||||
|
@ -294,15 +338,18 @@ int
|
|||
/* perform socks4 client dialog on existing FD.
|
||||
Called within fork/retry loop, after connect() */
|
||||
int _xioopen_socks4_connect(struct single *xfd,
|
||||
struct socks4 *sockhead,
|
||||
struct socks4request *sockhead,
|
||||
size_t headlen,
|
||||
int level) {
|
||||
ssize_t bytes;
|
||||
int wfd;
|
||||
int result;
|
||||
unsigned char buff[SIZEOF_STRUCT_SOCKS4];
|
||||
struct socks4 *replyhead = (struct socks4 *)buff;
|
||||
struct socks4head *replyhead = (struct socks4head *)buff;
|
||||
char *destdomname = NULL;
|
||||
|
||||
wfd = (xfd->fdtype == FDTYPE_SINGLE ? xfd->fd1 : xfd->fd2);
|
||||
|
||||
/* send socks header (target addr+port, +auth) */
|
||||
#if WITH_MSGLEVEL <= E_INFO
|
||||
if (ntohl(sockhead->dest) <= 0x000000ff) {
|
||||
|
@ -329,13 +376,16 @@ int _xioopen_socks4_connect(struct single *xfd,
|
|||
}
|
||||
#endif /* WITH_MSGLEVEL <= E_DEBUG */
|
||||
do {
|
||||
result = Write(xfd->fd, sockhead, headlen);
|
||||
result = Write(wfd, sockhead, headlen);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
if (result < 0) {
|
||||
Msg4(level, "write(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd, sockhead, headlen, strerror(errno));
|
||||
if (Close(xfd->fd) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd, strerror(errno));
|
||||
wfd, sockhead, headlen, strerror(errno));
|
||||
if (Close(wfd) < 0) {
|
||||
Info2("close(%d): %s", wfd, strerror(errno));
|
||||
}
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER; /* retry complete open cycle */
|
||||
}
|
||||
|
@ -345,20 +395,26 @@ int _xioopen_socks4_connect(struct single *xfd,
|
|||
while (bytes >= 0) { /* loop over answer chunks until complete or error */
|
||||
/* receive socks answer */
|
||||
do {
|
||||
result = Read(xfd->fd, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes);
|
||||
result = Read(xfd->fd1, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
if (result < 0) {
|
||||
Msg4(level, "read(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes,
|
||||
xfd->fd1, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes,
|
||||
strerror(errno));
|
||||
if (Close(xfd->fd) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd, strerror(errno));
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
}
|
||||
if (Close(wfd) < 0) {
|
||||
Info2("close(%d): %s", wfd, strerror(errno));
|
||||
}
|
||||
}
|
||||
if (result == 0) {
|
||||
Msg(level, "read(): EOF during read of socks reply, peer might not be a socks4 server");
|
||||
if (Close(xfd->fd) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd, strerror(errno));
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Info2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
}
|
||||
if (Close(wfd) < 0) {
|
||||
Info2("close(%d): %s", wfd, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
|
19
xio-socks.h
19
xio-socks.h
|
@ -1,36 +1,37 @@
|
|||
/* $Id: xio-socks.h,v 1.6 2004/06/06 19:03:28 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2004 */
|
||||
/* $Id: xio-socks.h,v 1.6.2.1 2006/07/24 19:18:30 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_socks_h_included
|
||||
#define __xio_socks_h_included 1
|
||||
|
||||
struct socks4 {
|
||||
#define SIZEOF_STRUCT_SOCKS4 sizeof(struct socks4head)
|
||||
|
||||
struct socks4request {
|
||||
uint8_t version;
|
||||
uint8_t action;
|
||||
uint16_t port;
|
||||
uint32_t dest;
|
||||
char userid[1]; /* just to have access via this struct */
|
||||
} ;
|
||||
#define SIZEOF_STRUCT_SOCKS4 8
|
||||
|
||||
extern const struct optdesc opt_socksport;
|
||||
extern const struct optdesc opt_socksuser;
|
||||
|
||||
extern const struct addrdesc addr_socks4_connect;
|
||||
extern const struct addrdesc addr_socks4a_connect;
|
||||
extern const union xioaddr_desc *xioaddrs_socks4_connect[];
|
||||
extern const union xioaddr_desc *xioaddrs_socks4a_connect[];
|
||||
|
||||
extern int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **socksport, struct socks4 *sockhead, size_t *headlen);
|
||||
extern int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **socksport, struct socks4request *sockhead, size_t *headlen);
|
||||
extern int
|
||||
_xioopen_socks4_connect0(struct single *xfd,
|
||||
const char *hostname, /* socks target host */
|
||||
int socks4a,
|
||||
struct socks4 *sockhead,
|
||||
struct socks4request *sockhead,
|
||||
ssize_t *headlen, /* get available space,
|
||||
return used length*/
|
||||
int level);
|
||||
extern int _xioopen_socks4_connect(struct single *xfd,
|
||||
struct socks4 *sockhead,
|
||||
struct socks4request *sockhead,
|
||||
size_t headlen,
|
||||
int level);
|
||||
|
||||
|
|
505
xio-socks5.c
Normal file
505
xio-socks5.c
Normal file
|
@ -0,0 +1,505 @@
|
|||
/* $Id$ */
|
||||
/* Copyright Gerhard Rieger 2004-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for opening addresses of socks5 type */
|
||||
|
||||
#include "xiosysincludes.h"
|
||||
#include "xioopen.h"
|
||||
#include "xio-socket.h"
|
||||
#include "xio-ipapp.h"
|
||||
|
||||
#include "xio-socks5.h"
|
||||
|
||||
|
||||
#if WITH_SOCKS5
|
||||
|
||||
#define SOCKSPORT "1080"
|
||||
#define SOCKS5_MAXLEN 512
|
||||
|
||||
static int
|
||||
xioopen_socks5_client(int argc, const char *argv[],
|
||||
struct opt *opts, int xioflags, xiofile_t *xfd,
|
||||
unsigned groups, int dummy1, int dummy2,
|
||||
int dummy3);
|
||||
|
||||
const struct optdesc opt_socks5_username = { "socks5-username", "socks5user", OPT_SOCKS5_USERNAME, GROUP_SOCKS5, PH_LATE, TYPE_STRING, OFUNC_SPEC };
|
||||
const struct optdesc opt_socks5_password = { "socks5-password", "socks5pass", OPT_SOCKS5_PASSWORD, GROUP_SOCKS5, PH_LATE, TYPE_STRING, OFUNC_SPEC };
|
||||
|
||||
static const struct xioaddr_inter_desc xiointer_socks5_client = { XIOADDR_PROT, "socks5", 2, XIOBIT_ALL, GROUP_SOCKS5, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socks5_client, 0, 0, 0, XIOBIT_RDWR HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_socks5_client[] = {
|
||||
(union xioaddr_desc *)&xiointer_socks5_client, NULL };
|
||||
|
||||
/* read until buflen bytes received or EOF */
|
||||
/* returns STAT_OK, STAT_RETRYLATER, or STAT_NOTRETRY */
|
||||
static int xiosocks5_recvbytes(struct single *xfd,
|
||||
uint8_t *buff, size_t buflen, int level) {
|
||||
size_t bytes;
|
||||
ssize_t result;
|
||||
|
||||
bytes = 0;
|
||||
while (bytes >= 0) { /* loop over answer chunks until complete or error */
|
||||
/* receive socks answer */
|
||||
Debug("waiting for data from peer");
|
||||
do {
|
||||
result = Read(xfd->fd1, buff+bytes, buflen-bytes);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
if (result < 0) {
|
||||
Msg4(level, "read(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd1, buff+bytes, buflen-bytes,
|
||||
strerror(errno));
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
}
|
||||
if (Close(xfd->fd2) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
if (result == 0) {
|
||||
Msg(level, "read(): EOF during read of socks reply");
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
}
|
||||
if (Close(xfd->fd2) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
bytes += result;
|
||||
if (bytes == buflen) {
|
||||
Debug1("received all "F_Zd" bytes", bytes);
|
||||
break;
|
||||
}
|
||||
Debug2("received "F_Zd" bytes, waiting for "F_Zu" more bytes",
|
||||
result, buflen-bytes);
|
||||
}
|
||||
if (result <= 0) { /* we had a problem while reading socks answer */
|
||||
return STAT_RETRYLATER; /* retry complete open cycle */
|
||||
}
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
static int xioopen_socks5_client(int argc, const char *argv[],
|
||||
struct opt *opts, int xioflags,
|
||||
xiofile_t *xxfd,
|
||||
unsigned groups, int dummy1, int dummy2,
|
||||
int dummy3) {
|
||||
/* we expect the form: host:port */
|
||||
xiosingle_t *xfd = &xxfd->stream;
|
||||
const char *targetname, *targetservice;
|
||||
int level;
|
||||
int result;
|
||||
|
||||
if (argc != 3) {
|
||||
Error("SOCKS5 syntax: socks5-connect:<host>:<port>"); /*! UDP? */
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
targetname = argv[1];
|
||||
targetservice = argv[2];
|
||||
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
applyopts_single(xfd, opts, PH_INIT);
|
||||
|
||||
#if 0
|
||||
result = _xioopen_socks5_prepare(a3, opts, &socksport, sockhead, &buflen);
|
||||
if (result != STAT_OK) return result;
|
||||
#endif
|
||||
|
||||
if (xfd->fd1 < 0) {
|
||||
Error("socks5 must be used as embedded address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Notice2("opening connection to %s:%s using socks5",
|
||||
targetname, targetservice);
|
||||
|
||||
do { /* loop over failed connect and socks-request attempts */
|
||||
|
||||
#if WITH_RETRY
|
||||
if (xfd->forever || xfd->retry) {
|
||||
level = E_INFO;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
level = E_ERROR;
|
||||
|
||||
#if 0
|
||||
/* we try to resolve the target address _before_ connecting to the socks
|
||||
server: this avoids unnecessary socks connects and timeouts */
|
||||
result =
|
||||
_xioopen_socks5_connect0(xfd, targetname, sockhead, opts,
|
||||
(ssize_t *)&buflen, level);
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
#if WITH_RETRY
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (xfd->forever || xfd->retry--) {
|
||||
if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL);
|
||||
continue;
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (xfd->fd1 < 0) {
|
||||
/* this cannot fork because we retrieved fork option above */
|
||||
result =
|
||||
_xioopen_connect (xfd,
|
||||
needbind?(struct sockaddr *)us:NULL, sizeof(*us),
|
||||
(struct sockaddr *)them, sizeof(struct sockaddr_in),
|
||||
opts, PF_INET, socktype, IPPROTO_TCP, lowport, level);
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
#if WITH_RETRY
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (xfd->forever || xfd->retry--) {
|
||||
if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL);
|
||||
continue;
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
xfd->fd1 = xfd->fd2 = xfd->fd;
|
||||
} else
|
||||
#endif
|
||||
xfd->dtype = XIODATA_STREAM;
|
||||
|
||||
result =
|
||||
_xioopen_socks5_connect(xfd, targetname, targetservice, opts, level);
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
#if WITH_RETRY
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (xfd->forever || xfd->retry--) {
|
||||
if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL);
|
||||
continue;
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!*/
|
||||
applyopts(xfd->fd1, opts, PH_ALL);
|
||||
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
return result;
|
||||
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
} while (true); /* end of complete open loop - drop out on success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* perform socks5 client dialog on existing FD.
|
||||
Called within fork/retry loop, after connect() */
|
||||
int _xioopen_socks5_connect(struct single *xfd,
|
||||
const char *targetname, const char *targetservice,
|
||||
struct opt *opts, int level) {
|
||||
uint16_t targetport;
|
||||
unsigned char sendbuff[SOCKS5_MAXLEN]; size_t sendlen;
|
||||
unsigned char recvbuff[SOCKS5_MAXLEN];
|
||||
struct socks5_method *sendmethod;
|
||||
struct socks5_select *recvselect;
|
||||
struct socks5_request *sendrequest;
|
||||
struct socks5_reply *recvreply;
|
||||
size_t namelen;
|
||||
size_t addrlen;
|
||||
size_t readpos;
|
||||
char *emsg;
|
||||
int result;
|
||||
|
||||
/* prepare */
|
||||
targetport = parseport(targetservice, IPPROTO_TCP/*!*/);
|
||||
|
||||
/* just the simplest authentications */
|
||||
sendmethod = (struct socks5_method *)sendbuff;
|
||||
sendmethod->version = 5; /* protocol version */
|
||||
sendmethod->nmethods = 2; /* number of proposed authentication types */
|
||||
sendmethod->methods[0] = SOCKS5_METHOD_NOAUTH; /* no auth at all */
|
||||
sendmethod->methods[1] = SOCKS5_METHOD_USERPASS; /* username/password */
|
||||
/*sendmethod->methods[2] = SOCKS5_METHOD_AVENTAIL;*/ /* Aventail Connect */
|
||||
sendlen = 2+sendmethod->nmethods;
|
||||
|
||||
/* send socks header (target addr+port, +auth) */
|
||||
Info("sending socks5 identifier/method selection message");
|
||||
do {
|
||||
result = Write(xfd->fd2, sendmethod, sendlen);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
if (result < 0) {
|
||||
Msg4(level, "write(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd2, sendmethod, sendlen, strerror(errno));
|
||||
if (Close(xfd->fd2) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
}
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER; /* retry complete open cycle */
|
||||
}
|
||||
|
||||
Info1("waiting for socks5 select reply ("F_Zu" bytes)", SOCKS5_SELECT_LENGTH);
|
||||
if ((result =
|
||||
xiosocks5_recvbytes(xfd, recvbuff, SOCKS5_SELECT_LENGTH, level)) !=
|
||||
STAT_OK) {
|
||||
/* we had a problem while reading socks answer */
|
||||
/*! Close(); */
|
||||
return result; /* ev. retry complete open cycle */
|
||||
}
|
||||
recvselect = (struct socks5_select *)recvbuff;
|
||||
Info2("socks5 select: {%u, %u}", recvselect->version, recvselect->method);
|
||||
if (recvselect->version != 5) {
|
||||
Error1("socks5: server protocol version is %u",
|
||||
recvbuff[0]);
|
||||
}
|
||||
if (recvselect->method == SOCKS5_METHOD_NONE) {
|
||||
Error("socks5: server did not accept our authentication methods");
|
||||
}
|
||||
/*! check if selected methods is one of our proposals */
|
||||
|
||||
switch (recvselect->method) {
|
||||
case SOCKS5_METHOD_NOAUTH:
|
||||
break;
|
||||
case SOCKS5_METHOD_USERPASS:
|
||||
if (xio_socks5_username_password(level, opts, xfd) < 0) {
|
||||
Error("username/password not accepted");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Error("socks5 select: unimplemented authentication method selected");
|
||||
break;
|
||||
}
|
||||
|
||||
sendrequest = (struct socks5_request *)sendbuff;
|
||||
sendrequest->version = SOCKS5_VERSION;
|
||||
sendrequest->command = SOCKS5_COMMAND_CONNECT;
|
||||
sendrequest->reserved = 0;
|
||||
sendrequest->addrtype = SOCKS5_ADDRTYPE_NAME;
|
||||
switch (sendrequest->addrtype) {
|
||||
case SOCKS5_ADDRTYPE_IPV4:
|
||||
break;
|
||||
case SOCKS5_ADDRTYPE_NAME:
|
||||
if ((namelen = strlen(targetname)) > 255) {
|
||||
Error1("socks5: target name is longer than 255 bytes: \"%s\"",
|
||||
targetname);
|
||||
}
|
||||
sendrequest->destaddr[0] = strlen(targetname);
|
||||
strncpy(sendrequest->destaddr+1, targetname, sizeof(sendbuff)-5);
|
||||
break;
|
||||
case SOCKS5_ADDRTYPE_IPV6:
|
||||
break;
|
||||
default: Fatal("socks5: undefined address type in socks request");
|
||||
}
|
||||
*((uint16_t *)&sendrequest->destaddr[strlen(targetname)+1]) = targetport;
|
||||
sendlen = sizeof(struct socks5_request) + namelen + 2;
|
||||
|
||||
/* send socks request (target addr+port, +auth) */
|
||||
Info("sending socks5 request selection");
|
||||
do {
|
||||
result = Write(xfd->fd2, sendrequest, sendlen);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
if (result < 0) {
|
||||
Msg4(level, "write(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd2, sendmethod, sendlen, strerror(errno));
|
||||
if (Close(xfd->fd2) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
}
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER; /* retry complete open cycle */
|
||||
}
|
||||
|
||||
Info("waiting for socks5 reply");
|
||||
recvreply = (struct socks5_reply *)recvbuff;
|
||||
if ((result =
|
||||
xiosocks5_recvbytes(xfd, recvbuff, SOCKS5_REPLY_LENGTH1, level))
|
||||
!= STAT_OK) {
|
||||
/*! close... */
|
||||
return result;
|
||||
}
|
||||
if (recvreply->version != SOCKS5_VERSION) {
|
||||
Error1("socks5: version of reply is %d", recvreply->version);
|
||||
}
|
||||
switch (recvreply->reply) {
|
||||
case SOCKS5_REPLY_SUCCESS: emsg = NULL; break;
|
||||
case SOCKS5_REPLY_FAILURE: emsg = "general socks server failure"; break;
|
||||
case SOCKS5_REPLY_DENIED: emsg = "connection not allowed by ruleset"; break;
|
||||
case SOCKS5_REPLY_NETUNREACH: emsg = "network unreachable"; break;
|
||||
case SOCKS5_REPLY_HOSTUNREACH: emsg = "host unreachable"; break;
|
||||
case SOCKS5_REPLY_REFUSED: emsg = "connection refused"; break;
|
||||
case SOCKS5_REPLY_TTLEXPIRED: emsg = "TTL expired"; break;
|
||||
case SOCKS5_REPLY_CMDUNSUPP: emsg = "command not supported"; break;
|
||||
case SOCKS5_REPLY_ADDRUNSUPP: emsg = "address type not supported"; break;
|
||||
default: emsg = "undefined error code"; break;
|
||||
}
|
||||
if (recvreply->reply != SOCKS5_REPLY_SUCCESS) {
|
||||
Error1("socks5 reply: %s", emsg);
|
||||
}
|
||||
|
||||
switch (recvreply->addrtype) {
|
||||
case SOCKS5_ADDRTYPE_IPV4:
|
||||
addrlen = 4; /*!*/
|
||||
if ((result =
|
||||
xiosocks5_recvbytes(xfd, recvbuff+SOCKS5_REPLY_LENGTH1, addrlen,
|
||||
level))
|
||||
!= STAT_OK) {
|
||||
/*! close... */
|
||||
return result;
|
||||
}
|
||||
readpos = sizeof(recvreply)-1+4;
|
||||
break;
|
||||
case SOCKS5_ADDRTYPE_NAME:
|
||||
/* read 1 byte containing domain name length */
|
||||
if ((result =
|
||||
xiosocks5_recvbytes(xfd, recvbuff+SOCKS5_REPLY_LENGTH1, 1, level))
|
||||
!= STAT_OK) {
|
||||
/*! close... */
|
||||
return result;
|
||||
}
|
||||
/* read domain name */
|
||||
if ((result =
|
||||
xiosocks5_recvbytes(xfd, recvbuff+SOCKS5_REPLY_LENGTH1+1,
|
||||
recvreply->destaddr[0], level))
|
||||
!= STAT_OK) {
|
||||
/*! close... */
|
||||
return result;
|
||||
}
|
||||
readpos = sizeof(recvreply)+recvreply->destaddr[0];
|
||||
addrlen = recvreply->destaddr[0]+1;
|
||||
break;
|
||||
case SOCKS5_ADDRTYPE_IPV6:
|
||||
addrlen = 16; /*!*/
|
||||
if ((result =
|
||||
xiosocks5_recvbytes(xfd, recvbuff+SOCKS5_REPLY_LENGTH1, addrlen,
|
||||
level))
|
||||
== EOF) {
|
||||
/*! close... */
|
||||
return result;
|
||||
}
|
||||
readpos = sizeof(recvreply)-1+4;
|
||||
break;
|
||||
default: Error("socks5: undefined address type in answer");
|
||||
addrlen = 0;
|
||||
readpos = sizeof(recvreply)-1;
|
||||
}
|
||||
if ((result =
|
||||
xiosocks5_recvbytes(xfd, recvbuff+readpos, 2, level))
|
||||
!= STAT_OK) {
|
||||
/*! close... */
|
||||
return result;
|
||||
}
|
||||
|
||||
/*! Infos(...); */
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
int xio_socks5_username_password(int level, struct opt *opts,
|
||||
struct single *xfd) {
|
||||
/*!!! */
|
||||
unsigned char sendbuff[513];
|
||||
unsigned char *pos;
|
||||
char *username = NULL;
|
||||
char *password = NULL;
|
||||
unsigned char recvbuff[2];
|
||||
struct socks5_userpass_reply *reply;
|
||||
int result;
|
||||
|
||||
retropt_string(opts, OPT_SOCKS5_USERNAME, (char **)&username);
|
||||
if (username == NULL) {
|
||||
Error("socks5: username required");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
retropt_string(opts, OPT_SOCKS5_PASSWORD, (char **)&password);
|
||||
if (password == NULL) {
|
||||
Error("socks5: password required");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
pos = sendbuff;
|
||||
*pos++ = SOCKS5_USERPASS_VERSION;
|
||||
*pos++ = strlen(username);
|
||||
strncpy(pos, username, 255);
|
||||
pos += strlen(username);
|
||||
*pos++ = strlen(password);
|
||||
strncpy(pos, password, 255);
|
||||
pos += strlen(password);
|
||||
|
||||
result =
|
||||
xio_socks5_dialog(level, xfd, sendbuff, pos-sendbuff,
|
||||
recvbuff, 2,
|
||||
"username/password authentication");
|
||||
if (result != STAT_OK) {
|
||||
Msg(level, "socks5 username/password dialog failed");
|
||||
return result;
|
||||
}
|
||||
Info("socks5 username/password authentication succeeded");
|
||||
reply = (struct socks5_userpass_reply *)recvbuff;
|
||||
if (reply->version != SOCKS5_USERPASS_VERSION) {
|
||||
Msg(level, "socks5 username/password authentication version mismatch");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
if (reply->status != SOCKS5_REPLY_SUCCESS) {
|
||||
Msg(level, "socks5 username/password authentication failure");
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
int xio_socks5_dialog(int level, struct single *xfd,
|
||||
unsigned char *sendbuff, size_t sendlen,
|
||||
unsigned char *recvbuff, size_t recvlen,
|
||||
const char *descr /* identifier/method selection */) {
|
||||
int result;
|
||||
|
||||
/* send socks header (target addr+port, +auth) */
|
||||
Info1("sending socks5 %s message", descr);
|
||||
do {
|
||||
result = Write(xfd->fd2, sendbuff, sendlen);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
if (result < 0) {
|
||||
Msg4(level, "write(%d, %p, "F_Zu"): %s",
|
||||
xfd->fd2, sendbuff, sendlen, strerror(errno));
|
||||
if (Close(xfd->fd2) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd2, strerror(errno));
|
||||
}
|
||||
if (Close(xfd->fd1) < 0) {
|
||||
Warn2("close(%d): %s", xfd->fd1, strerror(errno));
|
||||
}
|
||||
return STAT_RETRYLATER; /* retry complete open cycle */
|
||||
}
|
||||
|
||||
Info2("waiting for socks5 %s reply ("F_Zu" bytes)",
|
||||
descr, recvlen);
|
||||
if ((result =
|
||||
xiosocks5_recvbytes(xfd, recvbuff, recvlen, level))
|
||||
== EOF) {
|
||||
/* we had a problem while reading socks answer */
|
||||
/*! Close(); */
|
||||
return result; /* retry complete open cycle */
|
||||
}
|
||||
#if 0
|
||||
replyversion = ((struct socks5_version *)recvbuff)->version;
|
||||
Info1("socks5 server reply version: {%u}", replyversion);
|
||||
if (replyversion != SOCKS5_VERSION) {
|
||||
Error1("socks5: server protocol version is %u",
|
||||
replyversion);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* WITH_SOCKS5 */
|
||||
|
107
xio-socks5.h
Normal file
107
xio-socks5.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
/* $Id$ */
|
||||
/* Copyright Gerhard Rieger 2004-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_socks5_h_included
|
||||
#define __xio_socks5_h_included 1
|
||||
|
||||
#define SOCKS5_VERSION 5
|
||||
|
||||
#define SOCKS5_METHOD_NOAUTH 0x00
|
||||
#define SOCKS5_METHOD_GSSAPI 0x01
|
||||
#define SOCKS5_METHOD_USERPASS 0x02
|
||||
#define SOCKS5_METHOD_AVENTAIL 0x86 /*!*/
|
||||
#define SOCKS5_METHOD_NONE 0xff
|
||||
|
||||
#define SOCKS5_COMMAND_CONNECT 0x01
|
||||
#define SOCKS5_COMMAND_BIND 0x02
|
||||
#define SOCKS5_COMMAND_UDPASSOC 0x03
|
||||
|
||||
#define SOCKS5_ADDRTYPE_IPV4 0x01
|
||||
#define SOCKS5_ADDRTYPE_NAME 0x03
|
||||
#define SOCKS5_ADDRTYPE_IPV6 0x04
|
||||
|
||||
#define SOCKS5_REPLY_SUCCESS 0x00
|
||||
#define SOCKS5_REPLY_FAILURE 0x01
|
||||
#define SOCKS5_REPLY_DENIED 0x02
|
||||
#define SOCKS5_REPLY_NETUNREACH 0x03
|
||||
#define SOCKS5_REPLY_HOSTUNREACH 0x04
|
||||
#define SOCKS5_REPLY_REFUSED 0x05
|
||||
#define SOCKS5_REPLY_TTLEXPIRED 0x06
|
||||
#define SOCKS5_REPLY_CMDUNSUPP 0x07
|
||||
#define SOCKS5_REPLY_ADDRUNSUPP 0x08
|
||||
|
||||
#define SOCKS5_USERPASS_VERSION 0x01
|
||||
|
||||
/* just the first byte of server replies */
|
||||
struct socks5_version {
|
||||
uint8_t version;
|
||||
} ;
|
||||
|
||||
/* the version/method selection message of the client */
|
||||
struct socks5_method {
|
||||
uint8_t version;
|
||||
uint8_t nmethods;
|
||||
uint8_t methods[1]; /* has variable length, see nmethods */
|
||||
} ;
|
||||
|
||||
/* the selection message of the server */
|
||||
struct socks5_select {
|
||||
uint8_t version;
|
||||
uint8_t method;
|
||||
} ;
|
||||
#define SOCKS5_SELECT_LENGTH sizeof(struct socks5_select)
|
||||
|
||||
/* the request message */
|
||||
struct socks5_request {
|
||||
uint8_t version;
|
||||
uint8_t command;
|
||||
uint8_t reserved;
|
||||
uint8_t addrtype;
|
||||
uint8_t destaddr[1]; /* has variable length */
|
||||
/*uint16_t destport;*/ /* position depends on length of destaddr */
|
||||
} ;
|
||||
|
||||
/* the request message */
|
||||
struct socks5_reply {
|
||||
uint8_t version;
|
||||
uint8_t reply;
|
||||
uint8_t reserved;
|
||||
uint8_t addrtype;
|
||||
uint8_t destaddr[1]; /* has variable length */
|
||||
/*uint16_t destport;*/ /* position depends on length of destaddr */
|
||||
} ;
|
||||
#define SOCKS5_REPLY_LENGTH1 4 /*!*/ /* the fixed size fields */
|
||||
|
||||
/* the username/password authentication reply */
|
||||
struct socks5_userpass_reply {
|
||||
uint8_t version; /* authentication version, not socks version */
|
||||
uint8_t status;
|
||||
} ;
|
||||
|
||||
#if 0
|
||||
extern const struct optdesc opt_socksport;
|
||||
extern const struct optdesc opt_socksuser;
|
||||
#endif
|
||||
extern const struct optdesc opt_socks5_username;
|
||||
extern const struct optdesc opt_socks5_password;
|
||||
|
||||
extern const union xioaddr_desc *xioaddrs_socks5_client[];
|
||||
|
||||
extern int
|
||||
_xioopen_socks5_connect0(struct single *xfd,
|
||||
const char *targetname, const char *targetservice,
|
||||
int level);
|
||||
extern int _xioopen_socks5_connect(struct single *xfd,
|
||||
const char *targetname,
|
||||
const char *targetservice,
|
||||
struct opt *opts,
|
||||
int level);
|
||||
extern int xio_socks5_dialog(int level, struct single *xfd,
|
||||
unsigned char *sendbuff, size_t sendlen,
|
||||
unsigned char *recvbuff, size_t recvlen,
|
||||
const char *descr);
|
||||
extern int xio_socks5_username_password(int level, struct opt *opts,
|
||||
struct single *xfd);
|
||||
|
||||
#endif /* !defined(__xio_socks5_h_included) */
|
70
xio-stdio.c
70
xio-stdio.c
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xio-stdio.c,v 1.18 2006/12/28 14:07:01 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for opening addresses stdio type */
|
||||
|
@ -20,49 +20,51 @@ static int xioopen_stdfd(int argc, const char *argv[], struct opt *opts, int xio
|
|||
/* we specify all option groups that we can imagine for a FD, becasue the
|
||||
changed parsing mechanism does not allow us to check the type of FD before
|
||||
applying the options */
|
||||
const struct addrdesc addr_stdio = { "stdio", 3, xioopen_stdio, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 0, 0, 0 HELP(NULL) };
|
||||
const struct addrdesc addr_stdin = { "stdin", 1, xioopen_stdfd, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 0, 0, 0 HELP(NULL) };
|
||||
const struct addrdesc addr_stdout = { "stdout", 2, xioopen_stdfd, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 1, 0, 0 HELP(NULL) };
|
||||
const struct addrdesc addr_stderr = { "stderr", 2, xioopen_stdfd, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 2, 0, 0 HELP(NULL) };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_stdio0 = { XIOADDR_SYS, "stdio", 0, XIOBIT_ALL, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_stdio, 0, 0, 0 HELP(NULL) };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_stdin0 = { XIOADDR_SYS, "stdin", 0, XIOBIT_RDONLY, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_stdfd, 0, 0, 0 HELP(NULL) };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_stdout0 = { XIOADDR_SYS, "stdout", 0, XIOBIT_WRONLY, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_stdfd, 1, 0, 0 HELP(NULL) };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_stderr0 = { XIOADDR_SYS, "stderr", 0, XIOBIT_WRONLY, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_stdfd, 2, 0, 0 HELP(NULL) };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_stdio[] = {
|
||||
(union xioaddr_desc *)&xioaddr_stdio0, NULL };
|
||||
const union xioaddr_desc *xioaddrs_stdin[] = {
|
||||
(union xioaddr_desc *)&xioaddr_stdin0, NULL };
|
||||
const union xioaddr_desc *xioaddrs_stdout[] = {
|
||||
(union xioaddr_desc *)&xioaddr_stdout0, NULL };
|
||||
const union xioaddr_desc *xioaddrs_stderr[] = {
|
||||
(union xioaddr_desc *)&xioaddr_stderr0, NULL };
|
||||
|
||||
/* process a bidirectional "stdio" or "-" argument with options.
|
||||
generate a dual address. */
|
||||
int xioopen_stdio_bi(xiofile_t *sock) {
|
||||
struct opt *opts1, *opts2, *optspr;
|
||||
unsigned int groups1 = addr_stdio.groups, groups2 = addr_stdio.groups;
|
||||
unsigned int groups1 = xioaddr_stdio0.groups, groups2 = xioaddr_stdio0.groups;
|
||||
int result;
|
||||
|
||||
if (xioopen_makedual(sock) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sock->dual.stream[0]->tag = XIO_TAG_RDONLY;
|
||||
sock->dual.stream[0]->fd = 0 /*stdin*/;
|
||||
sock->dual.stream[1]->tag = XIO_TAG_WRONLY;
|
||||
sock->dual.stream[1]->fd = 1 /*stdout*/;
|
||||
sock->dual.stream[0]->howtoend =
|
||||
sock->dual.stream[1]->howtoend = END_NONE;
|
||||
sock->stream.fd1 = 0 /*stdin*/;
|
||||
sock->stream.fd2 = 1 /*stdout*/;
|
||||
sock->stream.fdtype = FDTYPE_DOUBLE;
|
||||
|
||||
#if WITH_TERMIOS
|
||||
if (Isatty(sock->dual.stream[0]->fd)) {
|
||||
if (Tcgetattr(sock->dual.stream[0]->fd,
|
||||
&sock->dual.stream[0]->savetty)
|
||||
if (Isatty(sock->stream.fd1)) {
|
||||
if (Tcgetattr(sock->stream.fd1,
|
||||
&sock->stream.savetty)
|
||||
< 0) {
|
||||
Warn2("cannot query current terminal settings on fd %d: %s",
|
||||
sock->dual.stream[0]->fd, strerror(errno));
|
||||
sock->stream.fd1, strerror(errno));
|
||||
} else {
|
||||
sock->dual.stream[0]->ttyvalid = true;
|
||||
sock->stream.ttyvalid = true;
|
||||
}
|
||||
}
|
||||
if (Isatty(sock->dual.stream[1]->fd)) {
|
||||
if (Tcgetattr(sock->dual.stream[1]->fd,
|
||||
&sock->dual.stream[1]->savetty)
|
||||
if (Isatty(sock->stream.fd2)) {
|
||||
if (Tcgetattr(sock->stream.fd2,
|
||||
&sock->stream.savetty)
|
||||
< 0) {
|
||||
Warn2("cannot query current terminal settings on fd %d: %s",
|
||||
sock->dual.stream[1]->fd, strerror(errno));
|
||||
|
||||
sock->stream.fd2, strerror(errno));
|
||||
} else {
|
||||
sock->dual.stream[1]->ttyvalid = true;
|
||||
sock->stream.ttyvalid = true;
|
||||
}
|
||||
}
|
||||
#endif /* WITH_TERMIOS */
|
||||
|
@ -71,7 +73,7 @@ int xioopen_stdio_bi(xiofile_t *sock) {
|
|||
applyopts(-1, sock->stream.opts, PH_INIT);
|
||||
|
||||
/* options here are one-time and one-direction, no second use */
|
||||
retropt_bool(sock->stream.opts, OPT_IGNOREEOF, &sock->dual.stream[0]->ignoreeof);
|
||||
retropt_bool(sock->stream.opts, OPT_IGNOREEOF, &sock->stream.ignoreeof);
|
||||
|
||||
/* extract opts that should be applied only once */
|
||||
if ((optspr = copyopts(sock->stream.opts, GROUP_PROCESS)) == NULL) {
|
||||
|
@ -88,10 +90,10 @@ int xioopen_stdio_bi(xiofile_t *sock) {
|
|||
}
|
||||
|
||||
/* apply options to first FD */
|
||||
if ((result = applyopts(sock->dual.stream[0]->fd, opts1, PH_ALL)) < 0) {
|
||||
if ((result = applyopts(sock->stream.fd1, opts1, PH_ALL)) < 0) {
|
||||
return result;
|
||||
}
|
||||
if ((result = _xio_openlate(sock->dual.stream[0], opts1)) < 0) {
|
||||
if ((result = _xio_openlate(&sock->stream, opts1)) < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -99,14 +101,14 @@ int xioopen_stdio_bi(xiofile_t *sock) {
|
|||
return -1;
|
||||
}
|
||||
/* apply options to second FD */
|
||||
if ((result = applyopts(sock->dual.stream[1]->fd, opts2, PH_ALL)) < 0) {
|
||||
if ((result = applyopts(sock->stream.fd2, opts2, PH_ALL)) < 0) {
|
||||
return result;
|
||||
}
|
||||
if ((result = _xio_openlate(sock->dual.stream[1], opts2)) < 0) {
|
||||
if ((result = _xio_openlate(&sock->stream, opts2)) < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((result = _xio_openlate(sock->dual.stream[1], optspr)) < 0) {
|
||||
if ((result = _xio_openlate(&sock->stream, optspr)) < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -131,7 +133,7 @@ static int xioopen_stdio(int argc, const char *argv[], struct opt *opts, int xio
|
|||
Notice2("using %s for %s",
|
||||
&("stdin\0\0\0stdout"[rw<<3]),
|
||||
ddirection[rw]);
|
||||
return xioopen_fd(opts, rw, &fd->stream, rw, dummy2, dummy3);
|
||||
return xioopen_fd(opts, rw, fd, rw, -1, dummy2, dummy3);
|
||||
}
|
||||
|
||||
/* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw.
|
||||
|
@ -145,6 +147,6 @@ static int xioopen_stdfd(int argc, const char *argv[], struct opt *opts, int xio
|
|||
Notice2("using %s for %s",
|
||||
&("stdin\0\0\0stdout\0\0stderr"[fd<<3]),
|
||||
ddirection[rw]);
|
||||
return xioopen_fd(opts, rw, &xfd->stream, fd, dummy2, dummy3);
|
||||
return xioopen_fd(opts, rw, xfd, fd, -1, dummy2, dummy3);
|
||||
}
|
||||
#endif /* WITH_STDIO */
|
||||
|
|
13
xio-stdio.h
13
xio-stdio.h
|
@ -1,17 +1,16 @@
|
|||
/* $Id: xio-stdio.h,v 1.5 2006/02/08 19:47:03 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* $Id: xio-stdio.h,v 1.5.2.1 2006/07/24 19:18:35 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_stdio_h_included
|
||||
#define __xio_stdio_h_included 1
|
||||
|
||||
|
||||
|
||||
extern int xioopen_stdio_bi(xiofile_t *sock);
|
||||
|
||||
extern const struct addrdesc addr_stdio;
|
||||
extern const struct addrdesc addr_stdin;
|
||||
extern const struct addrdesc addr_stdout;
|
||||
extern const struct addrdesc addr_stderr;
|
||||
extern const union xioaddr_desc *xioaddrs_stdio[];
|
||||
extern const union xioaddr_desc *xioaddrs_stdin[];
|
||||
extern const union xioaddr_desc *xioaddrs_stdout[];
|
||||
extern const union xioaddr_desc *xioaddrs_stderr[];
|
||||
|
||||
#endif /* !defined(__xio_stdio_h_included) */
|
||||
|
|
12
xio-system.c
12
xio-system.c
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xio-system.c,v 1.13 2006/03/21 20:53:38 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* $Id: xio-system.c,v 1.13.2.1 2006/07/24 19:18:36 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for opening addresses of system type */
|
||||
|
@ -20,8 +20,12 @@ static int xioopen_system(int arg, const char *argv[], struct opt *opts,
|
|||
int dummy1, int dummy2, int dummy3
|
||||
);
|
||||
|
||||
const struct addrdesc addr_system = { "system", 3, xioopen_system, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, 1, 0, 0 HELP(":<shell-command>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_system1 = { XIOADDR_SYS, "system", 1, XIOBIT_ALL, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_system, 1, 0, 0 HELP(":<shell-command>") };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_system[] = {
|
||||
(union xioaddr_desc *)&xioendpoint_system1,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int xioopen_system(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, /* XIO_RDONLY etc. */
|
||||
|
@ -34,7 +38,7 @@ static int xioopen_system(int argc, const char *argv[], struct opt *opts,
|
|||
int result;
|
||||
const char *string = argv[1];
|
||||
|
||||
status = _xioopen_foxec(xioflags, &fd->stream, groups, &opts);
|
||||
status = _xioopen_foxec_end(xioflags, &fd->stream, groups, &opts);
|
||||
if (status < 0) return status;
|
||||
if (status == 0) { /* child */
|
||||
int numleft;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/* $Id: xio-system.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001 */
|
||||
/* $Id: xio-system.h,v 1.4.2.1 2006/07/24 19:18:38 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_system_h_included
|
||||
#define __xio_system_h_included 1
|
||||
|
||||
extern const struct addrdesc addr_system;
|
||||
extern const union xioaddr_desc *xioaddrs_system[];
|
||||
|
||||
#endif /* !defined(__xio_system_h_included) */
|
||||
|
|
22
xio-tcp.c
22
xio-tcp.c
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xio-tcp.c,v 1.24 2006/07/13 06:48:47 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* $Id: xio-tcp.c,v 1.24.2.1 2006/07/24 19:18:39 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for TCP related functions and options */
|
||||
|
@ -17,23 +17,29 @@
|
|||
/****** TCP addresses ******/
|
||||
|
||||
#if WITH_IP4 || WITH_IP6
|
||||
const struct addrdesc addr_tcp_connect = { "tcp-connect", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_UNSPEC HELP(":<host>:<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_tcp_connect2 = { XIOADDR_SYS, "tcp-connect", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_connect, SOCK_STREAM, IPPROTO_TCP, PF_UNSPEC HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_tcp_connect[] = { (union xioaddr_desc *)&xioendpoint_tcp_connect2, NULL };
|
||||
#if WITH_LISTEN
|
||||
const struct addrdesc addr_tcp_listen = { "tcp-listen", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_UNSPEC HELP(":<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_tcp_listen1 = { XIOADDR_SYS, "tcp-listen", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_listen, SOCK_STREAM, IPPROTO_TCP, PF_UNSPEC HELP(":<port>") };
|
||||
const union xioaddr_desc *xioaddrs_tcp_listen[] = { (union xioaddr_desc *)&xioendpoint_tcp_listen1, NULL };
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if WITH_IP4
|
||||
const struct addrdesc addr_tcp4_connect = { "tcp4-connect", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_INET HELP(":<host>:<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_tcp4_connect2 = { XIOADDR_SYS, "tcp4-connect", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_connect, SOCK_STREAM, IPPROTO_TCP, PF_INET HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_tcp4_connect[] = { (union xioaddr_desc *)&xioendpoint_tcp4_connect2, NULL };
|
||||
#if WITH_LISTEN
|
||||
const struct addrdesc addr_tcp4_listen = { "tcp4-listen", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_INET HELP(":<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_tcp4_listen1 = { XIOADDR_SYS, "tcp4-listen", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_listen, SOCK_STREAM, IPPROTO_TCP, PF_INET HELP(":<port>") };
|
||||
const union xioaddr_desc *xioaddrs_tcp4_listen[] = { (union xioaddr_desc *)&xioendpoint_tcp4_listen1, NULL };
|
||||
#endif
|
||||
#endif /* WITH_IP4 */
|
||||
|
||||
#if WITH_IP6
|
||||
const struct addrdesc addr_tcp6_connect = { "tcp6-connect", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_INET6 HELP(":<host>:<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_tcp6_connect2 = { XIOADDR_SYS, "tcp6-connect", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_connect, SOCK_STREAM, IPPROTO_TCP, PF_INET6 HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_tcp6_connect[] = {(union xioaddr_desc *) &xioendpoint_tcp6_connect2, NULL };
|
||||
#if WITH_LISTEN
|
||||
const struct addrdesc addr_tcp6_listen = { "tcp6-listen", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_INET6 HELP(":<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_tcp6_listen1 = { XIOADDR_SYS, "tcp6-listen", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_listen, SOCK_STREAM, IPPROTO_TCP, PF_INET6 HELP(":<port>") };
|
||||
const union xioaddr_desc *xioaddrs_tcp6_listen[] = { (union xioaddr_desc *)&xioendpoint_tcp6_listen1, NULL };
|
||||
#endif
|
||||
#endif /* WITH_IP6 */
|
||||
|
||||
|
|
16
xio-tcp.h
16
xio-tcp.h
|
@ -1,16 +1,16 @@
|
|||
/* $Id: xio-tcp.h,v 1.12 2006/03/21 20:59:34 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* $Id: xio-tcp.h,v 1.12.2.1 2006/07/24 19:18:42 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_tcp_h_included
|
||||
#define __xio_tcp_h_included 1
|
||||
|
||||
extern const struct addrdesc addr_tcp_connect;
|
||||
extern const struct addrdesc addr_tcp_listen;
|
||||
extern const struct addrdesc addr_tcp4_connect;
|
||||
extern const struct addrdesc addr_tcp4_listen;
|
||||
extern const struct addrdesc addr_tcp6_connect;
|
||||
extern const struct addrdesc addr_tcp6_listen;
|
||||
extern const union xioaddr_desc *xioaddrs_tcp_connect[];
|
||||
extern const union xioaddr_desc *xioaddrs_tcp_listen[];
|
||||
extern const union xioaddr_desc *xioaddrs_tcp4_connect[];
|
||||
extern const union xioaddr_desc *xioaddrs_tcp4_listen[];
|
||||
extern const union xioaddr_desc *xioaddrs_tcp6_connect[];
|
||||
extern const union xioaddr_desc *xioaddrs_tcp6_listen[];
|
||||
|
||||
extern const struct optdesc opt_tcp_nodelay;
|
||||
extern const struct optdesc opt_tcp_maxseg;
|
||||
|
|
|
@ -131,11 +131,11 @@ int xio_tcpwrap_check(xiosingle_t *xfd, union sockaddr_union *us,
|
|||
Warn1("inet_ntop(): %s", strerror(errno));
|
||||
}
|
||||
Debug7("request_init(%p, RQ_FILE, %d, RQ_CLIENT_SIN, {%s:%u}, RQ_SERVER_SIN, {%s:%u}, RQ_DAEMON, \"%s\", 0",
|
||||
&ri, xfd->fd, clientaddr,
|
||||
&ri, xfd->fd1, clientaddr,
|
||||
ntohs(((struct sockaddr_in *)them)->sin_port),
|
||||
serveraddr, ntohs(us->ip4.sin_port),
|
||||
xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p'));
|
||||
request_init(&ri, RQ_FILE, xfd->fd,
|
||||
request_init(&ri, RQ_FILE, xfd->fd1,
|
||||
RQ_CLIENT_SIN, them,
|
||||
RQ_SERVER_SIN, &us->soa,
|
||||
RQ_DAEMON, xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p'), 0);
|
||||
|
|
228
xio-test.c
Normal file
228
xio-test.c
Normal file
|
@ -0,0 +1,228 @@
|
|||
/* $Id$ */
|
||||
/* Copyright Gerhard Rieger 2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for an intermediate test address that appends
|
||||
'>' to every block transferred from right to left, and '<' in the other
|
||||
direction */
|
||||
|
||||
#include "xiosysincludes.h"
|
||||
#include "xioopen.h"
|
||||
|
||||
#include "xio-test.h"
|
||||
|
||||
|
||||
#if WITH_TEST
|
||||
|
||||
static int xioopen_test(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups, int dummy1, int dummy2,
|
||||
int dummy3);
|
||||
static int xioopen_testuni(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups, int dummy1, int dummy2,
|
||||
int dummy3);
|
||||
static int xioopen_testrev(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups, int dummy1, int dummy2,
|
||||
int dummy3);
|
||||
|
||||
static const struct xioaddr_inter_desc xiointer_test0ro = { XIOADDR_PROT, "test", 0, XIOBIT_RDONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_test, 0, 0, 0, XIOBIT_WRONLY HELP("") };
|
||||
static const struct xioaddr_inter_desc xiointer_test0wo = { XIOADDR_PROT, "test", 0, XIOBIT_WRONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_test, 0, 0, 0, XIOBIT_RDONLY HELP("") };
|
||||
static const struct xioaddr_inter_desc xiointer_test0rw = { XIOADDR_PROT, "test", 0, XIOBIT_RDWR, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_test, 0, 0, 0, XIOBIT_RDWR HELP("") };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_test[] = {
|
||||
(union xioaddr_desc *)&xiointer_test0ro,
|
||||
(union xioaddr_desc *)&xiointer_test0wo,
|
||||
(union xioaddr_desc *)&xiointer_test0rw,
|
||||
NULL };
|
||||
|
||||
|
||||
static const struct xioaddr_inter_desc xiointer_testuni = { XIOADDR_PROT, "testuni", 0, XIOBIT_WRONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_testuni, 0, 0, 0, XIOBIT_RDONLY HELP("") };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_testuni[] = {
|
||||
(union xioaddr_desc *)&xiointer_testuni,
|
||||
NULL };
|
||||
|
||||
|
||||
static const struct xioaddr_inter_desc xiointer_testrev = { XIOADDR_PROT, "testrev", 0, XIOBIT_WRONLY, 0/*groups*/, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_testrev, 0, 0, 0, XIOBIT_RDONLY HELP("") };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_testrev[] = {
|
||||
(union xioaddr_desc *)&xiointer_testrev,
|
||||
NULL };
|
||||
|
||||
static int xioopen_test(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups, int dummy, int dummy2,
|
||||
int dummy3) {
|
||||
struct single *xfd = &xxfd->stream;
|
||||
int result;
|
||||
|
||||
assert(argc == 1);
|
||||
assert(!(xfd->fd1 < 0 && xfd->fd2 < 0));
|
||||
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
|
||||
Notice("opening TEST");
|
||||
xfd->dtype = XIODATA_TEST;
|
||||
applyopts(xfd->fd1, opts, PH_ALL);
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xioopen_testuni(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups, int dummy, int dummy2,
|
||||
int dummy3) {
|
||||
struct single *xfd = &xxfd->stream;
|
||||
int result;
|
||||
|
||||
assert(argc == 1);
|
||||
assert(!(xfd->fd1 < 0 && xfd->fd2 < 0));
|
||||
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
|
||||
Notice("opening TESTUNI");
|
||||
xfd->dtype = XIODATA_TESTUNI;
|
||||
applyopts(xfd->fd1, opts, PH_ALL);
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xioopen_testrev(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd,
|
||||
unsigned groups, int dummy, int dummy2,
|
||||
int dummy3) {
|
||||
struct single *xfd = &xxfd->stream;
|
||||
int result;
|
||||
|
||||
assert(argc == 1);
|
||||
assert(!(xfd->fd1 < 0 && xfd->fd2 < 0));
|
||||
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
|
||||
Notice("opening TESTREV");
|
||||
xfd->dtype = XIODATA_TESTREV;
|
||||
applyopts(xfd->fd1, opts, PH_ALL);
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t xioread_test(struct single *sfd, void *buff, size_t bufsiz) {
|
||||
int fd = sfd->fd1;
|
||||
ssize_t bytes;
|
||||
int _errno;
|
||||
|
||||
do {
|
||||
bytes = Read(fd, buff, bufsiz-1);
|
||||
} while (bytes < 0 && errno == EINTR);
|
||||
if (bytes < 0) {
|
||||
_errno = errno;
|
||||
switch (_errno) {
|
||||
case EPIPE: case ECONNRESET:
|
||||
Warn4("read(%d, %p, "F_Zu"): %s",
|
||||
fd, buff, bufsiz-1, strerror(_errno));
|
||||
break;
|
||||
default:
|
||||
Error4("read(%d, %p, "F_Zu"): %s",
|
||||
fd, buff, bufsiz-1, strerror(_errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (bytes == 0) {
|
||||
return 0;
|
||||
}
|
||||
((char *)buff)[bytes] = '<';
|
||||
return bytes+1;
|
||||
}
|
||||
|
||||
size_t xiowrite_test(struct single *sfd, const void *buff, size_t bytes) {
|
||||
int fd = ((sfd->fdtype==FDTYPE_DOUBLE)?sfd->fd2:sfd->fd1);
|
||||
void *buff1;
|
||||
ssize_t writt;
|
||||
int _errno;
|
||||
|
||||
if ((buff1 = Malloc(bytes+1)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(buff1, buff, bytes);
|
||||
((char *)buff1)[bytes] = '>';
|
||||
do {
|
||||
writt = Write(fd, buff1, bytes+1);
|
||||
} while (writt < 0 && errno == EINTR);
|
||||
if (writt < 0) {
|
||||
_errno = errno;
|
||||
switch (_errno) {
|
||||
case EPIPE:
|
||||
case ECONNRESET:
|
||||
if (sfd->cool_write) {
|
||||
Notice4("write(%d, %p, "F_Zu"): %s",
|
||||
fd, buff1, bytes+1, strerror(_errno));
|
||||
break;
|
||||
}
|
||||
/*PASSTHROUGH*/
|
||||
default:
|
||||
Error4("write(%d, %p, "F_Zu"): %s",
|
||||
fd, buff1, bytes+1, strerror(_errno));
|
||||
}
|
||||
errno = _errno;
|
||||
free(buff1);
|
||||
return -1;
|
||||
}
|
||||
if ((size_t)writt < bytes) {
|
||||
Warn2("write() only wrote "F_Zu" of "F_Zu" bytes",
|
||||
writt, bytes+1);
|
||||
}
|
||||
free(buff1);
|
||||
return writt;
|
||||
}
|
||||
|
||||
size_t xiowrite_testrev(struct single *sfd, const void *buff, size_t bytes) {
|
||||
int fd = ((sfd->fdtype==FDTYPE_DOUBLE)?sfd->fd2:sfd->fd1);
|
||||
void *buff1;
|
||||
ssize_t writt;
|
||||
int _errno;
|
||||
|
||||
if ((buff1 = Malloc(bytes+1)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(buff1, buff, bytes);
|
||||
((char *)buff1)[bytes] = '<';
|
||||
do {
|
||||
writt = Write(fd, buff1, bytes+1);
|
||||
} while (writt < 0 && errno == EINTR);
|
||||
if (writt < 0) {
|
||||
_errno = errno;
|
||||
switch (_errno) {
|
||||
case EPIPE:
|
||||
case ECONNRESET:
|
||||
if (sfd->cool_write) {
|
||||
Notice4("write(%d, %p, "F_Zu"): %s",
|
||||
fd, buff1, bytes+1, strerror(_errno));
|
||||
break;
|
||||
}
|
||||
/*PASSTHROUGH*/
|
||||
default:
|
||||
Error4("write(%d, %p, "F_Zu"): %s",
|
||||
fd, buff1, bytes+1, strerror(_errno));
|
||||
}
|
||||
errno = _errno;
|
||||
free(buff1);
|
||||
return -1;
|
||||
}
|
||||
if ((size_t)writt < bytes) {
|
||||
Warn2("write() only wrote "F_Zu" of "F_Zu" bytes",
|
||||
writt, bytes+1);
|
||||
}
|
||||
free(buff1);
|
||||
return writt;
|
||||
}
|
||||
|
||||
#endif /* WITH_TEST */
|
||||
|
16
xio-test.h
Normal file
16
xio-test.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* $Id$ */
|
||||
/* Copyright Gerhard Rieger 2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_test_h_included
|
||||
#define __xio_test_h_included 1
|
||||
|
||||
extern const union xioaddr_desc *xioaddrs_test[];
|
||||
extern const union xioaddr_desc *xioaddrs_testuni[];
|
||||
extern const union xioaddr_desc *xioaddrs_testrev[];
|
||||
|
||||
extern size_t xioread_test(struct single *sfd, void *buff, size_t bufsiz);
|
||||
extern size_t xiowrite_test(struct single *sfd, const void *buff, size_t bytes);
|
||||
extern size_t xiowrite_testrev(struct single *sfd, const void *buff, size_t bytes);
|
||||
|
||||
#endif /* !defined(__xio_test_h_included) */
|
24
xio-tun.c
24
xio-tun.c
|
@ -46,7 +46,13 @@ const struct optdesc opt_iff_automedia = { "iff-automedia", "automedia", O
|
|||
const struct optdesc opt_route = { "route", NULL, OPT_ROUTE, GROUP_INTERFACE, PH_INIT, TYPE_STRING, OFUNC_SPEC };
|
||||
#endif
|
||||
|
||||
const struct addrdesc xioaddr_tun = { "tun", 3, xioopen_tun, GROUP_FD|GROUP_CHR|GROUP_NAMED|GROUP_OPEN|GROUP_TUN, 0, 0, 0 HELP(":<ip-addr>/<bits>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_tun1 = { XIOADDR_SYS, "tun", 1, XIOBIT_ALL, GROUP_FD|GROUP_CHR|GROUP_NAMED|GROUP_OPEN|GROUP_TUN, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_tun, 0, 0, 0 HELP(":<ip-addr>/<bits>") };
|
||||
|
||||
const union xioaddr_desc *xioaddrs_tun[] = {
|
||||
(union xioaddr_desc *)&xioendpoint_tun1,
|
||||
NULL
|
||||
};
|
||||
|
||||
// "if-name"=tun3
|
||||
// "route"=address/netmask
|
||||
// "ip6-route"=address/netmask
|
||||
|
@ -101,7 +107,7 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
|
|||
Notice("creating tunnel network interface");
|
||||
if ((result = _xioopen_open(tundevice, rw, opts)) < 0)
|
||||
return result;
|
||||
xfd->stream.fd = result;
|
||||
xfd->stream.fd1 = result;
|
||||
|
||||
/* prepare configuration of the new network interface */
|
||||
memset(&ifr, 0,sizeof(ifr));
|
||||
|
@ -132,10 +138,10 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
|
|||
}
|
||||
}
|
||||
|
||||
if (Ioctl(xfd->stream.fd, TUNSETIFF, &ifr) < 0) {
|
||||
if (Ioctl(xfd->stream.fd1, TUNSETIFF, &ifr) < 0) {
|
||||
Error3("ioctl(%d, TUNSETIFF, {\"%s\"}: %s",
|
||||
xfd->stream.fd, ifr.ifr_name, strerror(errno));
|
||||
Close(xfd->stream.fd);
|
||||
xfd->stream.fd1, ifr.ifr_name, strerror(errno));
|
||||
Close(xfd->stream.fd1);
|
||||
}
|
||||
|
||||
/*===================== setting interface properties =====================*/
|
||||
|
@ -143,7 +149,7 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
|
|||
/* we seem to need a socket for manipulating the interface */
|
||||
if ((sockfd = Socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
Error1("socket(PF_INET, SOCK_DGRAM, 0): %s", strerror(errno));
|
||||
sockfd = xfd->stream.fd; /* desparate fallback attempt */
|
||||
sockfd = xfd->stream.fd1; /* desparate fallback attempt */
|
||||
}
|
||||
|
||||
/*--------------------- setting interface address and netmask ------------*/
|
||||
|
@ -195,10 +201,10 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
|
|||
#if LATER
|
||||
applyopts_named(tundevice, opts, PH_FD);
|
||||
#endif
|
||||
applyopts(xfd->stream.fd, opts, PH_FD);
|
||||
applyopts_cloexec(xfd->stream.fd, opts);
|
||||
applyopts(xfd->stream.fd1, opts, PH_FD);
|
||||
applyopts_cloexec(xfd->stream.fd1, opts);
|
||||
|
||||
applyopts_fchown(xfd->stream.fd, opts);
|
||||
applyopts_fchown(xfd->stream.fd1, opts);
|
||||
|
||||
if ((result = _xio_openlate(&xfd->stream, opts)) < 0)
|
||||
return result;
|
||||
|
|
|
@ -28,6 +28,6 @@ extern const struct optdesc opt_iff_portsel;
|
|||
extern const struct optdesc opt_iff_automedia;
|
||||
/*extern const struct optdesc opt_iff_dynamic;*/
|
||||
|
||||
extern const struct addrdesc xioaddr_tun;
|
||||
extern const union xioaddr_desc *xioaddrs_tun[];
|
||||
|
||||
#endif /* !defined(__xio_tun_h_included) */
|
||||
|
|
110
xio-udp.c
110
xio-udp.c
|
@ -35,42 +35,59 @@ static
|
|||
int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xfd, unsigned groups,
|
||||
int pf, int socktype, int ipproto);
|
||||
|
||||
static
|
||||
int _xioopen_udp_sendto(const char *hostname, const char *servname,
|
||||
struct opt *opts,
|
||||
int xioflags, xiofile_t *xxfd, unsigned groups,
|
||||
int pf, int socktype, int ipproto);
|
||||
|
||||
const struct addrdesc addr_udp_connect = { "udp-connect", 3, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP, SOCK_DGRAM, IPPROTO_UDP, PF_UNSPEC HELP(":<host>:<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp_connect2 = { XIOADDR_SYS, "udp-connect", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_connect, SOCK_DGRAM, IPPROTO_UDP, PF_UNSPEC HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp_connect[] = { (union xioaddr_desc *)&xioaddr_udp_connect2, NULL };
|
||||
#if WITH_LISTEN
|
||||
const struct addrdesc addr_udp_listen = { "udp-listen", 3, xioopen_ipdgram_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, PF_UNSPEC, IPPROTO_UDP, PF_UNSPEC HELP(":<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp_listen1 = { XIOADDR_SYS, "udp-listen", 1, XIOBIT_RDONLY|XIO_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipdgram_listen, PF_UNSPEC, IPPROTO_UDP, PF_UNSPEC HELP(":<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp_listen[] = { (union xioaddr_desc *)&xioaddr_udp_listen1, NULL };
|
||||
#endif /* WITH_LISTEN */
|
||||
const struct addrdesc addr_udp_sendto = { "udp-sendto", 3, xioopen_udp_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
|
||||
const struct addrdesc addr_udp_recvfrom = { "udp-recvfrom", 3, xioopen_udp_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
|
||||
const struct addrdesc addr_udp_recv = { "udp-recv", 1, xioopen_udp_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
|
||||
const struct addrdesc addr_udp_datagram = { "udp-datagram", 3, xioopen_udp_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp_sendto2 = { XIOADDR_SYS, "udp-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_sendto, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp_sendto[] = { (union xioaddr_desc *)&xioaddr_udp_sendto2, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp_recvfrom1 = { XIOADDR_SYS, "udp-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_udp_recvfrom, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp_recvfrom[] = { (union xioaddr_desc *)&xioaddr_udp_recvfrom1, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp_recv1 = { XIOADDR_SYS, "udp-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_recv, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp_recv[] = { (union xioaddr_desc *)&xioaddr_udp_recv1, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp_datagram2 = { XIOADDR_SYS, "udp-datagram", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_datagram, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp_datagram[] = { (union xioaddr_desc *)&xioaddr_udp_datagram2, NULL };
|
||||
|
||||
#if WITH_IP4
|
||||
const struct addrdesc addr_udp4_connect = { "udp4-connect", 3, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP, SOCK_DGRAM, IPPROTO_UDP, PF_INET HELP(":<host>:<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp4_connect2 = { XIOADDR_SYS, "udp4-connect", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_connect, SOCK_DGRAM, IPPROTO_UDP, PF_INET HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp4_connect[] = { (union xioaddr_desc *)&xioaddr_udp4_connect2, NULL };
|
||||
#if WITH_LISTEN
|
||||
const struct addrdesc addr_udp4_listen = { "udp4-listen", 3, xioopen_ipdgram_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, PF_INET, IPPROTO_UDP, PF_INET HELP(":<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp4_listen1 = { XIOADDR_SYS, "udp4-listen", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipdgram_listen, PF_INET, IPPROTO_UDP, PF_INET HELP(":<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp4_listen[] = { (union xioaddr_desc *)&xioaddr_udp4_listen1, NULL };
|
||||
#endif /* WITH_LISTEN */
|
||||
const struct addrdesc addr_udp4_sendto = { "udp4-sendto", 3, xioopen_udp_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
|
||||
const struct addrdesc addr_udp4_datagram = { "udp4-datagram",3, xioopen_udp_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_RANGE, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<remote-address>:<port>") };
|
||||
const struct addrdesc addr_udp4_recvfrom= { "udp4-recvfrom", 3, xioopen_udp_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
|
||||
const struct addrdesc addr_udp4_recv = { "udp4-recv", 1, xioopen_udp_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_RANGE, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp4_sendto2 = { XIOADDR_SYS, "udp4-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_sendto, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp4_sendto[] = { (union xioaddr_desc *)&xioaddr_udp4_sendto2, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp4_datagram2= { XIOADDR_SYS, "udp4-datagram",2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_datagram, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp4_datagram[] = { (union xioaddr_desc *)&xioaddr_udp4_datagram2, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp4_recvfrom1= { XIOADDR_SYS, "udp4-recvfrom",1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_udp_recvfrom, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp4_recvfrom[] = { (union xioaddr_desc *)&xioaddr_udp4_recvfrom1, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp4_recv1 = { XIOADDR_SYS, "udp4-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_recv, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp4_recv[] = { (union xioaddr_desc *)&xioaddr_udp4_recv1, NULL };
|
||||
#endif /* WITH_IP4 */
|
||||
|
||||
#if WITH_IP6
|
||||
const struct addrdesc addr_udp6_connect = { "udp6-connect", 3, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP, SOCK_DGRAM, IPPROTO_UDP, PF_INET6 HELP(":<host>:<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp6_connect2 = { XIOADDR_SYS, "udp6-connect", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipapp_connect, SOCK_DGRAM, IPPROTO_UDP, PF_INET6 HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp6_connect[] = { (union xioaddr_desc *)&xioaddr_udp6_connect2, NULL };
|
||||
#if WITH_LISTEN
|
||||
const struct addrdesc addr_udp6_listen = { "udp6-listen", 3, xioopen_ipdgram_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, PF_INET6, IPPROTO_UDP, 0 HELP(":<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp6_listen1 = { XIOADDR_SYS, "udp6-listen", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_ipdgram_listen, PF_INET6, IPPROTO_UDP, 0 HELP(":<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp6_listen[] = { (union xioaddr_desc *)&xioaddr_udp6_listen1, NULL };
|
||||
#endif /* WITH_LISTEN */
|
||||
const struct addrdesc addr_udp6_sendto = { "udp6-sendto", 3, xioopen_udp_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
|
||||
const struct addrdesc addr_udp6_datagram= { "udp6-datagram", 3, xioopen_udp_datagram,GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
|
||||
const struct addrdesc addr_udp6_recvfrom= { "udp6-recvfrom", 3, xioopen_udp_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
|
||||
const struct addrdesc addr_udp6_recv = { "udp6-recv", 1, xioopen_udp_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp6_sendto2 = { XIOADDR_SYS, "udp6-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_sendto, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp6_sendto[] = { (union xioaddr_desc *)&xioaddr_udp6_sendto2, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp6_datagram2= { XIOADDR_SYS, "udp6-datagram",2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_datagram, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<host>:<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp6_datagram[] = { (union xioaddr_desc *)&xioaddr_udp6_datagram2, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp6_recvfrom1= { XIOADDR_SYS, "udp6-recvfrom",1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, XIOSHUT_NONE, XIOCLOSE_NONE, xioopen_udp_recvfrom, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp6_recvfrom[] = { (union xioaddr_desc *)&xioaddr_udp6_recvfrom1, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioaddr_udp6_recv1 = { XIOADDR_SYS, "udp6-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_udp_recv, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":<port>") };
|
||||
const union xioaddr_desc *xioaddrs_udp6_recv[] = { (union xioaddr_desc *)&xioaddr_udp6_recv1, NULL };
|
||||
#endif /* WITH_IP6 */
|
||||
|
||||
|
||||
|
@ -113,6 +130,8 @@ 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_int(opts, OPT_SO_TYPE, &socktype);
|
||||
retropt_bind(opts, pf, socktype, IPPROTO_UDP,
|
||||
|
@ -172,61 +191,61 @@ 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.fd = Socket(pf, socktype, ipproto)) < 0) {
|
||||
if ((fd->stream.fd1 = Socket(pf, socktype, ipproto)) < 0) {
|
||||
Error4("socket(%d, %d, %d): %s", pf, socktype, ipproto, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
applyopts(fd->stream.fd, opts, PH_PASTSOCKET);
|
||||
if (Setsockopt(fd->stream.fd, opt_so_reuseaddr.major,
|
||||
/*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,
|
||||
opt_so_reuseaddr.minor, &one, sizeof(one)) < 0) {
|
||||
Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd"): %s",
|
||||
fd->stream.fd, opt_so_reuseaddr.major,
|
||||
fd->stream.fd1, opt_so_reuseaddr.major,
|
||||
opt_so_reuseaddr.minor, one, sizeof(one), strerror(errno));
|
||||
}
|
||||
applyopts_cloexec(fd->stream.fd, opts);
|
||||
applyopts(fd->stream.fd, opts, PH_PREBIND);
|
||||
applyopts(fd->stream.fd, opts, PH_BIND);
|
||||
if (Bind(fd->stream.fd, &us.soa, uslen) < 0) {
|
||||
Error4("bind(%d, {%s}, "F_Zd"): %s", fd->stream.fd,
|
||||
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,
|
||||
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.fd, &us.soa, &uslen) < 0) {
|
||||
if (Getsockname(fd->stream.fd1, &us.soa, &uslen) < 0) {
|
||||
Error4("getsockname(%d, %p, {%d}): %s",
|
||||
fd->stream.fd, &us.soa, uslen, strerror(errno));
|
||||
fd->stream.fd1, &us.soa, uslen, strerror(errno));
|
||||
}
|
||||
applyopts(fd->stream.fd, opts, PH_PASTBIND);
|
||||
applyopts(fd->stream.fd1, opts, PH_PASTBIND);
|
||||
|
||||
Notice1("listening on UDP %s",
|
||||
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)));
|
||||
FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt);
|
||||
FD_SET(fd->stream.fd, &in);
|
||||
while (Select(fd->stream.fd+1, &in, &out, &expt, NULL) < 0) {
|
||||
FD_SET(fd->stream.fd1, &in);
|
||||
while (Select(fd->stream.fd1+1, &in, &out, &expt, NULL) < 0) {
|
||||
if (errno != EINTR) break;
|
||||
}
|
||||
|
||||
themlen = socket_init(pf, them);
|
||||
do {
|
||||
result = Recvfrom(fd->stream.fd, buff1, 1, MSG_PEEK,
|
||||
result = Recvfrom(fd->stream.fd1, 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.fd, buff1,
|
||||
fd->stream.fd1, buff1,
|
||||
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
|
||||
themlen, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
Notice1("accepting UDP connection from %s",
|
||||
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)));
|
||||
|
||||
if (xiocheckpeer(&fd->stream, them, la) < 0) {
|
||||
/* drop packet */
|
||||
char buff[512];
|
||||
Recv(fd->stream.fd, buff, sizeof(buff), 0);
|
||||
Recv(fd->stream.fd1, buff, sizeof(buff), 0);
|
||||
continue;
|
||||
}
|
||||
Info1("permitting UDP connection from %s",
|
||||
|
@ -249,8 +268,8 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
|||
/* server: continue loop with select */
|
||||
/* 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.fd) < 0) {
|
||||
Info2("close(%d): %s", fd->stream.fd, strerror(errno));
|
||||
if (Close(fd->stream.fd1) < 0) {
|
||||
Info2("close(%d): %s", fd->stream.fd1, strerror(errno));
|
||||
}
|
||||
Notice1("forked off child process "F_pid, pid);
|
||||
Sleep(1); /*! give child a chance to consume the old packet */
|
||||
|
@ -260,18 +279,17 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
|||
break;
|
||||
}
|
||||
|
||||
applyopts(fd->stream.fd, opts, PH_CONNECT);
|
||||
if ((result = Connect(fd->stream.fd, &them->soa, themlen)) < 0) {
|
||||
applyopts(fd->stream.fd1, opts, PH_CONNECT);
|
||||
if ((result = Connect(fd->stream.fd1, &them->soa, themlen)) < 0) {
|
||||
Error4("connect(%d, {%s}, "F_Zd"): %s",
|
||||
fd->stream.fd,
|
||||
fd->stream.fd1,
|
||||
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
|
||||
themlen, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
fd->stream.howtoend = END_SHUTDOWN;
|
||||
applyopts_fchown(fd->stream.fd, opts);
|
||||
applyopts(fd->stream.fd, opts, PH_LATE);
|
||||
applyopts_fchown(fd->stream.fd1, opts);
|
||||
applyopts(fd->stream.fd1, opts, PH_LATE);
|
||||
|
||||
if ((result = _xio_openlate(&fd->stream, opts)) < 0)
|
||||
return result;
|
||||
|
@ -312,7 +330,6 @@ int _xioopen_udp_sendto(const char *hostname, const char *servname,
|
|||
bool needbind = false;
|
||||
int result;
|
||||
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
||||
|
||||
/* ...res_opts[] */
|
||||
|
@ -452,7 +469,6 @@ int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts,
|
|||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
xfd->stream.howtoend = END_NONE;
|
||||
retropt_socket_pf(opts, &pf);
|
||||
if (pf == PF_UNSPEC) {
|
||||
#if WITH_IP4 && WITH_IP6
|
||||
|
|
36
xio-udp.h
36
xio-udp.h
|
@ -5,24 +5,24 @@
|
|||
#ifndef __xio_udp_h_included
|
||||
#define __xio_udp_h_included 1
|
||||
|
||||
extern const struct addrdesc addr_udp_connect;
|
||||
extern const struct addrdesc addr_udp_listen;
|
||||
extern const struct addrdesc addr_udp_sendto;
|
||||
extern const struct addrdesc addr_udp_datagram;
|
||||
extern const struct addrdesc addr_udp_recvfrom;
|
||||
extern const struct addrdesc addr_udp_recv;
|
||||
extern const struct addrdesc addr_udp4_connect;
|
||||
extern const struct addrdesc addr_udp4_listen;
|
||||
extern const struct addrdesc addr_udp4_sendto;
|
||||
extern const struct addrdesc addr_udp4_datagram;
|
||||
extern const struct addrdesc addr_udp4_recvfrom;
|
||||
extern const struct addrdesc addr_udp4_recv;
|
||||
extern const struct addrdesc addr_udp6_connect;
|
||||
extern const struct addrdesc addr_udp6_listen;
|
||||
extern const struct addrdesc addr_udp6_sendto;
|
||||
extern const struct addrdesc addr_udp6_datagram;
|
||||
extern const struct addrdesc addr_udp6_recvfrom;
|
||||
extern const struct addrdesc addr_udp6_recv;
|
||||
extern const union xioaddr_desc *xioaddrs_udp_connect[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp_listen[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp_sendto[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp_datagram[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp_recvfrom[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp_recv[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp4_connect[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp4_listen[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp4_sendto[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp4_datagram[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp4_recvfrom[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp4_recv[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp6_connect[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp6_listen[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp6_sendto[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp6_datagram[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp6_recvfrom[];
|
||||
extern const union xioaddr_desc *xioaddrs_udp6_recv[];
|
||||
|
||||
extern int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
||||
int rw, xiofile_t *fd,
|
||||
|
|
50
xio-unix.c
50
xio-unix.c
|
@ -25,7 +25,6 @@ int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts,
|
|||
int pf, int socktype, int ipproto);
|
||||
static
|
||||
int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
|
||||
#if WITH_ABSTRACT_UNIXSOCKET
|
||||
static int xioopen_abstract_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
static int xioopen_abstract_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
|
@ -39,23 +38,36 @@ static
|
|||
int xioopen_abstract_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
#endif /* WITH_ABSTRACT_UNIXSOCKET */
|
||||
|
||||
const struct addrdesc addr_unix_connect = { "unix-connect", 3, xioopen_unix_connect, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_unix_connect1 = { XIOADDR_SYS, "unix-connect", 1, XIOBIT_ALL, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_connect, 0, SOCK_STREAM, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_unix_connect[] = { (union xioaddr_desc *)&xioendpoint_unix_connect1, NULL };
|
||||
#if WITH_LISTEN
|
||||
const struct addrdesc addr_unix_listen = { "unix-listen", 3, xioopen_unix_listen, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_unix_listen1 = { XIOADDR_SYS, "unix-listen", 1, XIOBIT_ALL, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_listen, 0, SOCK_STREAM, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_unix_listen[] = { (union xioaddr_desc *)&xioendpoint_unix_listen1, NULL };
|
||||
#endif /* WITH_LISTEN */
|
||||
const struct addrdesc addr_unix_sendto = { "unix-sendto", 3, xioopen_unix_sendto, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_DGRAM, 0 HELP(":<filename>") };
|
||||
const struct addrdesc addr_unix_recvfrom= { "unix-recvfrom", 3, xioopen_unix_recvfrom, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
|
||||
const struct addrdesc addr_unix_recv = { "unix-recv", 1, xioopen_unix_recv, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
|
||||
const struct addrdesc addr_unix_client = { "unix-client", 3, xioopen_unix_client, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, 0, 0 HELP(":<filename>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_unix_sendto1 = { XIOADDR_SYS, "unix-sendto", 1, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_sendto, 0, SOCK_DGRAM, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_unix_sendto[] = { (union xioaddr_desc *)&xioendpoint_unix_sendto1, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_unix_recvfrom1= { XIOADDR_SYS, "unix-recvfrom",1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_unix_recvfrom, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_unix_recvfrom[]= { (union xioaddr_desc *)&xioendpoint_unix_recvfrom1, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_unix_recv1 = { XIOADDR_SYS, "unix-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_unix_recv, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_unix_recv[] = { (union xioaddr_desc *)&xioendpoint_unix_recv1, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_unix_client1 = { XIOADDR_SYS, "unix-client", 1, XIOBIT_ALL, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_client, PF_UNIX, 0, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_unix_client[] = { (union xioaddr_desc *)&xioendpoint_unix_client1, NULL };
|
||||
|
||||
#if WITH_ABSTRACT_UNIXSOCKET
|
||||
const struct addrdesc xioaddr_abstract_connect = { "abstract-connect", 3, xioopen_abstract_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_abstract_connect1 = { XIOADDR_SYS, "abstract-connect", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_abstract_connect, 0, SOCK_STREAM, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_abstract_connect[] = { (union xioaddr_desc *)&xioendpoint_abstract_connect1, NULL };
|
||||
#if WITH_LISTEN
|
||||
const struct addrdesc xioaddr_abstract_listen = { "abstract-listen", 3, xioopen_abstract_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_abstract_listen1 = { XIOADDR_SYS, "abstract-listen", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_abstract_listen, 0, SOCK_STREAM, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_abstract_listen[] = { (union xioaddr_desc *)&xioendpoint_abstract_listen1, NULL };
|
||||
#endif /* WITH_LISTEN */
|
||||
const struct addrdesc xioaddr_abstract_sendto = { "abstract-sendto", 3, xioopen_abstract_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_DGRAM, 0 HELP(":<filename>") };
|
||||
const struct addrdesc xioaddr_abstract_recvfrom= { "abstract-recvfrom", 3, xioopen_abstract_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
|
||||
const struct addrdesc xioaddr_abstract_recv = { "abstract-recv", 1, xioopen_abstract_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
|
||||
const struct addrdesc xioaddr_abstract_client = { "abstract-client", 3, xioopen_abstract_client, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, 0, 0 HELP(":<filename>") };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_abstract_sendto1 = { XIOADDR_SYS, "abstract-sendto", 1, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_abstract_sendto, 0, SOCK_DGRAM, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_abstract_sendto[] = { (union xioaddr_desc *)&xioendpoint_abstract_sendto1, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_abstract_recvfrom1= { XIOADDR_SYS, "abstract-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_abstract_recvfrom, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_abstract_recvfrom[] = { (union xioaddr_desc *)&xioendpoint_abstract_recvfrom1, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_abstract_recv1 = { XIOADDR_SYS, "abstract-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_abstract_recv, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_abstract_recv[] = { (union xioaddr_desc *)&xioendpoint_abstract_recv1, NULL };
|
||||
static const struct xioaddr_endpoint_desc xioendpoint_abstract_client1 = { XIOADDR_SYS, "abstract-client", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_abstract_client, PF_UNIX, 0, 0 HELP(":<filename>") };
|
||||
const union xioaddr_desc *xioaddrs_abstract_client[] = { (union xioaddr_desc *)&xioendpoint_abstract_client1, NULL };
|
||||
#endif /* WITH_ABSTRACT_UNIXSOCKET */
|
||||
|
||||
const struct optdesc opt_unix_tightsocklen = { "unix-tightsocklen", "tightsocklen", OPT_UNIX_TIGHTSOCKLEN, GROUP_SOCK_UNIX, PH_INIT, TYPE_BOOL, OFUNC_SPEC, 0, 0 };
|
||||
|
@ -133,8 +145,6 @@ static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, i
|
|||
xfd->opt_unlink_close = true;
|
||||
}
|
||||
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_EARLY);
|
||||
|
@ -242,8 +252,6 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i
|
|||
uslen = socket_init(pf, &us);
|
||||
xfd->salen = socket_init(pf, &xfd->peersa);
|
||||
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
|
||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
||||
|
||||
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
|
||||
|
@ -299,7 +307,6 @@ int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts,
|
|||
name = argv[1];
|
||||
uslen = xiosetunix(&us, name, false, tight);
|
||||
|
||||
xfd->stream.howtoend = END_NONE;
|
||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
||||
retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0);
|
||||
retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
|
||||
|
@ -406,7 +413,6 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i
|
|||
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
|
||||
}
|
||||
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
||||
|
||||
uslen = socket_init(pf, &us);
|
||||
|
@ -487,8 +493,6 @@ static int xioopen_abstract_listen(int argc, const char *argv[], struct opt *opt
|
|||
name = argv[1];
|
||||
uslen = xiosetunix(&us, name, true, tight);
|
||||
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_EARLY);
|
||||
|
@ -574,8 +578,6 @@ static int xioopen_abstract_sendto(int argc, const char *argv[], struct opt *opt
|
|||
uslen = socket_init(pf, &us);
|
||||
xfd->salen = socket_init(pf, &xfd->peersa);
|
||||
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
|
||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
||||
|
||||
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
|
||||
|
@ -620,7 +622,6 @@ int xioopen_abstract_recvfrom(int argc, const char *argv[], struct opt *opts,
|
|||
name = argv[1];
|
||||
uslen = xiosetunix(&us, name, true, tight);
|
||||
|
||||
xfd->stream.howtoend = END_NONE;
|
||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
||||
retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0);
|
||||
|
||||
|
@ -685,7 +686,6 @@ static int xioopen_abstract_client(int argc, const char *argv[], struct opt *opt
|
|||
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
|
||||
}
|
||||
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
||||
|
||||
uslen = socket_init(pf, &us);
|
||||
|
|
24
xio-unix.h
24
xio-unix.h
|
@ -5,18 +5,18 @@
|
|||
#ifndef __xio_unix_h_included
|
||||
#define __xio_unix_h_included 1
|
||||
|
||||
extern const struct addrdesc addr_unix_connect;
|
||||
extern const struct addrdesc addr_unix_listen;
|
||||
extern const struct addrdesc addr_unix_sendto;
|
||||
extern const struct addrdesc addr_unix_recvfrom;
|
||||
extern const struct addrdesc addr_unix_recv;
|
||||
extern const struct addrdesc addr_unix_client;
|
||||
extern const struct addrdesc xioaddr_abstract_connect;
|
||||
extern const struct addrdesc xioaddr_abstract_listen;
|
||||
extern const struct addrdesc xioaddr_abstract_sendto;
|
||||
extern const struct addrdesc xioaddr_abstract_recvfrom;
|
||||
extern const struct addrdesc xioaddr_abstract_recv;
|
||||
extern const struct addrdesc xioaddr_abstract_client;
|
||||
extern const union xioaddr_desc *xioaddrs_unix_connect[];
|
||||
extern const union xioaddr_desc *xioaddrs_unix_listen[];
|
||||
extern const union xioaddr_desc *xioaddrs_unix_sendto[];
|
||||
extern const union xioaddr_desc *xioaddrs_unix_recvfrom[];
|
||||
extern const union xioaddr_desc *xioaddrs_unix_recv[];
|
||||
extern const union xioaddr_desc *xioaddrs_unix_client[];
|
||||
extern const union xioaddr_desc *xioaddrs_abstract_connect[];
|
||||
extern const union xioaddr_desc *xioaddrs_abstract_listen[];
|
||||
extern const union xioaddr_desc *xioaddrs_abstract_sendto[];
|
||||
extern const union xioaddr_desc *xioaddrs_abstract_recvfrom[];
|
||||
extern const union xioaddr_desc *xioaddrs_abstract_recv[];
|
||||
extern const union xioaddr_desc *xioaddrs_abstract_client[];
|
||||
|
||||
extern const struct optdesc opt_unix_tightsocklen;
|
||||
|
||||
|
|
309
xio.h
309
xio.h
|
@ -19,7 +19,7 @@
|
|||
#define LINETERM_CR 1
|
||||
#define LINETERM_CRNL 2
|
||||
|
||||
struct addrdesc;
|
||||
union xioaddr_desc;
|
||||
struct opt;
|
||||
|
||||
/* the flags argument of xioopen */
|
||||
|
@ -27,18 +27,37 @@ struct opt;
|
|||
#define XIO_WRONLY O_WRONLY /* asserted to be 1 */
|
||||
#define XIO_RDWR O_RDWR /* asserted to be 2 */
|
||||
#define XIO_ACCMODE O_ACCMODE /* must be 3 */
|
||||
#define XIO_MAYFORK 4 /* address is allowed to fork the program (fork) */
|
||||
#define XIO_MAYCHILD 8 /* address is allowed to fork off a child (exec)*/
|
||||
/* 3 is undefined */
|
||||
#define XIO_MAYFORK 4 /* address is allowed to fork the program (fork),
|
||||
especially with listen and connect addresses */
|
||||
#define XIO_MAYCHILD 8 /* address is allowed to fork off a child that
|
||||
exec's another program or calls system() */
|
||||
#define XIO_MAYEXEC 16 /* address is allowed to exec a prog (exec+nofork) */
|
||||
#define XIO_MAYCONVERT 32 /* address is allowed to perform modifications on the
|
||||
stream data, e.g. SSL, REALDINE; CRLF */
|
||||
stream data, e.g. SSL, READLINE; CRLF */
|
||||
#define XIO_MAYCHAIN 64 /* address is allowed to consist of a chain of
|
||||
subaddresses that are handled by socat
|
||||
subprocesses */
|
||||
#define XIO_EMBEDDED 256 /* address is nonterminal */
|
||||
#define XIO_MAYALL INT_MAX /* all features enabled */
|
||||
|
||||
/* the status flags of xiofile_t */
|
||||
#define XIO_DOESFORK XIO_MAYFORK
|
||||
#define XIO_DOESCHILD XIO_MAYCHILD
|
||||
#define XIO_DOESEXEC XIO_MAYEXEC
|
||||
#define XIO_DOESCONVERT XIO_MAYCONVERT
|
||||
#define XIO_DOESCHAIN XIO_MAYCHAIN
|
||||
|
||||
/* sometimes we use a set of allowed direction(s), a bit pattern */
|
||||
#define XIOBIT_RDONLY (1<<XIO_RDONLY)
|
||||
#define XIOBIT_WRONLY (1<<XIO_WRONLY)
|
||||
#define XIOBIT_RDWR (1<<XIO_RDWR)
|
||||
#define XIOBIT_ALL (XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR)
|
||||
#define XIOBIT_ALLRD (XIOBIT_RDONLY|XIOBIT_RDWR)
|
||||
#define XIOBIT_ALLWR (XIOBIT_WRONLY|XIOBIT_RDWR)
|
||||
#define XIOBIT_ONE (XIOBIT_RDONLY|XIOBIT_WRONLY)
|
||||
/* reverse the direction pattern */
|
||||
#define XIOBIT_REVERSE(x) (((x)&XIOBIT_RDWR)|(((x)&XIOBIT_RDONLY)?XIOBIT_WRONLY:0)|(((x)&XIOBIT_WRONLY)?XIOBIT_RDONLY:0))
|
||||
|
||||
/* methods for reading and writing, and for related checks */
|
||||
#define XIODATA_READMASK 0xf000 /* mask for basic r/w method */
|
||||
|
@ -47,6 +66,7 @@ struct opt;
|
|||
#define XIOREAD_PTY 0x4000 /* handle EIO */
|
||||
#define XIOREAD_READLINE 0x5000 /* ... */
|
||||
#define XIOREAD_OPENSSL 0x6000 /* SSL_read() */
|
||||
#define XIOREAD_TEST 0x7000 /* xioread_test() */
|
||||
#define XIODATA_WRITEMASK 0x0f00 /* mask for basic r/w method */
|
||||
#define XIOWRITE_STREAM 0x0100 /* write() (default) */
|
||||
#define XIOWRITE_SENDTO 0x0200 /* sendto() */
|
||||
|
@ -54,6 +74,8 @@ struct opt;
|
|||
#define XIOWRITE_2PIPE 0x0400 /* write() to alternate (2pipe) Fd */
|
||||
#define XIOWRITE_READLINE 0x0500 /* check for prompt */
|
||||
#define XIOWRITE_OPENSSL 0x0600 /* SSL_write() */
|
||||
#define XIOWRITE_TEST 0x0700 /* xiowrite_test() */
|
||||
#define XIOWRITE_TESTREV 0x0800 /* xiowrite_testrev() */
|
||||
/* modifiers to XIODATA_READ_RECV */
|
||||
#define XIOREAD_RECV_CHECKPORT 0x0001 /* recv, check peer port */
|
||||
#define XIOREAD_RECV_CHECKADDR 0x0002 /* recv, check peer address */
|
||||
|
@ -76,7 +98,46 @@ struct opt;
|
|||
#define XIODATA_PTY (XIOREAD_PTY|XIOWRITE_STREAM)
|
||||
#define XIODATA_READLINE (XIOREAD_READLINE|XIOWRITE_STREAM)
|
||||
#define XIODATA_OPENSSL (XIOREAD_OPENSSL|XIOWRITE_OPENSSL)
|
||||
#define XIODATA_TEST (XIOREAD_TEST|XIOWRITE_TEST)
|
||||
#define XIODATA_TESTUNI XIOWRITE_TEST
|
||||
#define XIODATA_TESTREV XIOWRITE_TESTREV
|
||||
|
||||
/* XIOSHUT_* define the actions on shutdown of the address */
|
||||
/* */
|
||||
#define XIOSHUTRD_MASK 0x00f0
|
||||
#define XIOSHUTWR_MASK 0x000f
|
||||
#define XIOSHUTSPEC_MASK 0xff00 /* specific action */
|
||||
#define XIOSHUTRD_UNSPEC 0x0000
|
||||
#define XIOSHUTWR_UNSPEC 0x0000
|
||||
#define XIOSHUTRD_NONE 0x0010 /* no action - e.g. stdin */
|
||||
#define XIOSHUTWR_NONE 0x0001 /* no action - e.g. stdout */
|
||||
#define XIOSHUTRD_CLOSE 0x0020 /* close() */
|
||||
#define XIOSHUTWR_CLOSE 0x0002 /* close() */
|
||||
#define XIOSHUTRD_DOWN 0x0030 /* shutdown(, SHUT_RD) */
|
||||
#define XIOSHUTWR_DOWN 0x0003 /* shutdown(, SHUT_WR) */
|
||||
#define XIOSHUTRD_SIGHUP 0x0040 /* kill sub process */
|
||||
#define XIOSHUTWR_SIGHUP 0x0004 /* flush sub process with SIGHPUP */
|
||||
#define XIOSHUTRD_SIGTERM 0x0050 /* kill sub process with SIGTERM */
|
||||
#define XIOSHUTWR_SIGTERM 0x0005 /* kill sub process with SIGTERM */
|
||||
#define XIOSHUTWR_SIGKILL 0x0006 /* kill sub process with SIGKILL */
|
||||
#define XIOSHUT_UNSPEC (XIOSHUTRD_UNSPEC|XIOSHUTWR_UNSPEC)
|
||||
#define XIOSHUT_NONE (XIOSHUTRD_NONE|XIOSHUTWR_NONE)
|
||||
#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 XIOCLOSE_UNSPEC 0x0000 /* after init, when no end-close... option */
|
||||
#define XIOCLOSE_NONE 0x0001 /* no action */
|
||||
#define XIOCLOSE_CLOSE 0x0002 /* close() */
|
||||
#define XIOCLOSE_SIGTERM 0x0003 /* send SIGTERM to sub process */
|
||||
#define XIOCLOSE_SIGKILL 0x0004 /* send SIGKILL to sub process */
|
||||
#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
|
||||
|
||||
/* these are the values allowed for the "enum xiotag tag" flag of the "struct
|
||||
single" and "union bipipe" (xiofile_t) structures. */
|
||||
|
@ -89,6 +150,88 @@ enum xiotag {
|
|||
streams */
|
||||
} ;
|
||||
|
||||
|
||||
union bipipe;
|
||||
|
||||
|
||||
#define XIOADDR_ENDPOINT 0 /* endpoint address */
|
||||
#define XIOADDR_INTER 1 /* inter address */
|
||||
#define XIOADDR_SYS XIOADDR_ENDPOINT
|
||||
#define XIOADDR_PROT XIOADDR_INTER
|
||||
|
||||
struct xioaddr_inter_desc {
|
||||
int tag; /* 0: endpoint addr; 1: inter addr */
|
||||
const char *defname; /* main (canonical) name of address */
|
||||
int numparams; /* number of required parameters */
|
||||
int leftdirs; /* set of data directions supported on left side:
|
||||
e.g. XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR */
|
||||
unsigned groups;
|
||||
int howtoshut;
|
||||
int howtoclose;
|
||||
int (*func)(int argc, const char *argv[], struct opt *opts, int rw, union bipipe *fd, unsigned groups,
|
||||
int arg1, int arg2, int arg3);
|
||||
int arg1;
|
||||
int arg2;
|
||||
int arg3;
|
||||
int rightdirs;
|
||||
#if WITH_HELP
|
||||
const char *syntax;
|
||||
#endif
|
||||
} ;
|
||||
|
||||
struct xioaddr_endpoint_desc {
|
||||
int tag; /* 0: endpoint addr; 1: inter addr */
|
||||
const char *defname; /* main (canonical) name of address */
|
||||
int numparams; /* number of required parameters */
|
||||
int leftdirs;
|
||||
unsigned groups;
|
||||
int howtoshut;
|
||||
int howtoclose;
|
||||
int (*func)(int argc, const char *argv[], struct opt *opts, int rw, union bipipe *fd, unsigned groups,
|
||||
int arg1, int arg2, int arg3);
|
||||
int arg1;
|
||||
int arg2;
|
||||
int arg3;
|
||||
#if WITH_HELP
|
||||
const char *syntax;
|
||||
#endif
|
||||
} ;
|
||||
|
||||
|
||||
struct xioaddr_common_desc {
|
||||
int tag; /* 0: endpoint addr; 1: inter addr */
|
||||
const char *defname; /* main (canonical) name of address */
|
||||
int numparams; /* number of required parameters */
|
||||
int leftdirs;
|
||||
unsigned groups;
|
||||
int howtoshut;
|
||||
int howtoclose;
|
||||
} ;
|
||||
|
||||
|
||||
union xioaddr_desc {
|
||||
int tag; /* 0: endpoint addr; 1: inter addr */
|
||||
struct xioaddr_common_desc common_desc;
|
||||
struct xioaddr_inter_desc inter_desc;
|
||||
struct xioaddr_endpoint_desc endpoint_desc;
|
||||
} ;
|
||||
|
||||
union xioaddr_descp {
|
||||
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;
|
||||
} ;
|
||||
|
||||
|
||||
/*!!! this to xio-sockd4.h */
|
||||
struct socks4head {
|
||||
uint8_t version;
|
||||
uint8_t action;
|
||||
uint16_t port;
|
||||
uint32_t dest;
|
||||
} ;
|
||||
|
||||
/* global XIO options/parameters */
|
||||
typedef struct {
|
||||
bool strictopts;
|
||||
|
@ -97,11 +240,22 @@ typedef struct {
|
|||
const char *optionsep;
|
||||
char ip4portsep;
|
||||
char ip6portsep; /* do not change, might be hardcoded somewhere! */
|
||||
char logopt; /* 'm' means "switch to syslog when entering daemon mode" */
|
||||
const char *syslogfac; /* syslog facility (only with mixed mode) */
|
||||
char default_ip; /* default prot.fam for IP based listen ('4' or '6') */
|
||||
char preferred_ip; /* preferred prot.fam. for name resolution ('0' for
|
||||
unspecified, '4', or '6') */
|
||||
char *reversechar;
|
||||
char *chainsep;
|
||||
size_t bufsiz;
|
||||
bool verbose;
|
||||
bool verbhex;
|
||||
bool debug;
|
||||
char logopt; /* y..syslog; s..stderr; f..file; m..mixed */
|
||||
struct timeval total_timeout;/* when nothing happens, die after seconds */
|
||||
struct timeval pollintv; /* with ignoreeof, reread after seconds */
|
||||
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 */
|
||||
} xioopts_t;
|
||||
|
||||
/* pack the description of a lock file */
|
||||
|
@ -111,14 +265,12 @@ typedef struct {
|
|||
struct timespec intervall; /* polling intervall */
|
||||
} xiolock_t;
|
||||
|
||||
extern xioopts_t xioopts;
|
||||
|
||||
#define MAXARGV 8
|
||||
|
||||
/* a non-dual file descriptor */
|
||||
typedef struct single {
|
||||
enum xiotag tag; /* see enum xiotag */
|
||||
const struct addrdesc *addr;
|
||||
const union xioaddr_desc *addrdesc;
|
||||
int flags;
|
||||
/* until here, keep consistent with bipipe.common !!! */
|
||||
#if WITH_RETRY
|
||||
|
@ -136,26 +288,41 @@ typedef struct single {
|
|||
size_t actbytes; /* so many bytes still to be read (when readbytes!=0)*/
|
||||
xiolock_t lock; /* parameters of lockfile */
|
||||
bool havelock; /* we are happy owner of the above lock */
|
||||
bool cool_write; /* downlevel EPIPE, ECONNRESET to notice */
|
||||
/* until here, keep consistent with bipipe.dual ! */
|
||||
int reverse; /* valid during parse and overload, before open:
|
||||
will this (inter) address be integrated forward or
|
||||
reverse? */
|
||||
const union xioaddr_desc **addrdescs;
|
||||
/* valid after parse, before overload:
|
||||
the list of possible address descriptors derived
|
||||
from addr keyword, one of which will be selected by
|
||||
context and num of parameters */
|
||||
int closing; /* 0..write channel is up, 1..just shutdown write ch.,
|
||||
2..counting down closing timeout, 3..no more write
|
||||
possible */
|
||||
bool cool_write; /* downlevel EPIPE, ECONNRESET to notice */
|
||||
int argc; /* number of fields in argv */
|
||||
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 fd;
|
||||
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;
|
||||
pid_t subaddrpid; /* pid of subaddress (process handling next addr in
|
||||
chain) */
|
||||
int subaddrstat; /* state of subaddress process
|
||||
0...no sub address process
|
||||
1...running
|
||||
-1...ended (aborted?) */
|
||||
int subaddrexit; /* if subaddstat==-1: exit code of sub process */
|
||||
bool opt_unlink_close; /* option unlink_close */
|
||||
char *unlink_close; /* name of a symlink or unix socket to be removed */
|
||||
int dtype;
|
||||
enum {
|
||||
END_UNSPEC, /* after init, when no end-close... option */
|
||||
END_NONE, /* no action */
|
||||
END_CLOSE, /* close() */
|
||||
END_SHUTDOWN, /* shutdown() */
|
||||
END_UNLINK, /* unlink() */
|
||||
END_KILL, /* has subprocess */
|
||||
END_CLOSE_KILL, /* first close fd, then kill subprocess */
|
||||
END_SHUTDOWN_KILL /* first shutdown fd, then kill subprocess */
|
||||
} howtoend;
|
||||
int howtoshut; /* method for shutting down xfds */
|
||||
int howtoclose; /* method for closing xfds */
|
||||
#if _WITH_SOCKET
|
||||
union sockaddr_union peersa;
|
||||
socklen_t salen;
|
||||
|
@ -164,13 +331,19 @@ typedef struct single {
|
|||
bool ttyvalid; /* the following struct is valid */
|
||||
struct termios savetty; /* save orig tty settings for later restore */
|
||||
#endif /* WITH_TERMIOS */
|
||||
const char *name; /* only with END_UNLINK */
|
||||
/*0 const char *name;*/ /* only with END_UNLINK */
|
||||
struct { /* this was for exec only, now for embedded */
|
||||
pid_t pid; /* child PID, with EXEC: */
|
||||
int (*sigchild)(struct single *); /* callback after sigchild */
|
||||
} child;
|
||||
pid_t ppid; /* parent pid, only if we send it signals */
|
||||
pthread_t subthread; /* thread handling next inter-addr in chain */
|
||||
union {
|
||||
#if 0
|
||||
struct {
|
||||
int fdout; /* use fd for output */
|
||||
} bipipe;
|
||||
#endif
|
||||
#if _WITH_SOCKET
|
||||
struct {
|
||||
struct timeval connect_timeout; /* how long to hang in connect() */
|
||||
|
@ -213,6 +386,37 @@ typedef struct single {
|
|||
#endif
|
||||
} readline;
|
||||
#endif /* WITH_READLINE */
|
||||
#if WITH_SOCKS4_SERVER
|
||||
struct {
|
||||
int state; /* state of socks4 protocol negotiation */
|
||||
/* we cannot rely on all request data arriving at once */
|
||||
struct socks4head head;
|
||||
char *userid;
|
||||
char *hostname; /* socks4a only */
|
||||
/* the following structs are an experiment for future synchronization
|
||||
mechanisms */
|
||||
struct {
|
||||
size_t canrecv;
|
||||
size_t wantwrite;
|
||||
void *inbuff;
|
||||
size_t inbuflen; /* length of buffer */
|
||||
size_t bytes; /* current bytes in buffer */
|
||||
} proto;
|
||||
struct {
|
||||
size_t canrecv;
|
||||
size_t wantwrite;
|
||||
} peer_proto;
|
||||
struct {
|
||||
size_t canrecv;
|
||||
size_t wantwrite;
|
||||
int _errno;
|
||||
} data;
|
||||
struct {
|
||||
size_t canrecv;
|
||||
size_t wantwrite;
|
||||
} peer_data;
|
||||
} socks4d;
|
||||
#endif /* WITH_SOCKS4_SERVER */
|
||||
#if WITH_OPENSSL
|
||||
struct {
|
||||
struct timeval connect_timeout; /* how long to hang in connect() */
|
||||
|
@ -225,6 +429,13 @@ typedef struct single {
|
|||
short iff_opts[2]; /* ifr flags, using OFUNC_OFFSET_MASKS */
|
||||
} tun;
|
||||
#endif /* WITH_TUN */
|
||||
#if _WITH_GZIP
|
||||
struct {
|
||||
gzFile in; /* for reading (uncompressing from stream to API) */
|
||||
gzFile out; /* for writing (compressing from API to stream) */
|
||||
int level;
|
||||
} gzip;
|
||||
#endif /* _WITH_GZIP */
|
||||
} para;
|
||||
} xiosingle_t;
|
||||
|
||||
|
@ -242,13 +453,13 @@ typedef union bipipe {
|
|||
enum xiotag tag;
|
||||
struct {
|
||||
enum xiotag tag;
|
||||
const struct addrdesc *addr;
|
||||
const union xioaddr_desc *addrdesc;
|
||||
int flags;
|
||||
} common;
|
||||
struct single stream;
|
||||
struct {
|
||||
enum xiotag tag;
|
||||
const struct addrdesc *addr;
|
||||
const union xioaddr_desc *addrdesc;
|
||||
int flags; /* compatible to fcntl(.., F_GETFL, ..) */
|
||||
#if WITH_RETRY
|
||||
unsigned retry; /* retry opening this many times */
|
||||
|
@ -262,31 +473,19 @@ typedef union bipipe {
|
|||
size_t actbytes; /* so many bytes still to be read */
|
||||
xiolock_t lock; /* parameters of lockfile */
|
||||
bool havelock; /* we are happy owner of the above lock */
|
||||
/* until here, keep consistent with struct single ! */
|
||||
xiosingle_t *stream[2]; /* input stream, output stream */
|
||||
} dual;
|
||||
} xiofile_t;
|
||||
|
||||
|
||||
struct addrdesc {
|
||||
const char *defname; /* main (canonical) name of address */
|
||||
int directions; /* 1..read, 2..write, 3..both */
|
||||
int (*func)(int argc, const char *argv[], struct opt *opts, int rw, xiofile_t *fd, unsigned groups,
|
||||
int arg1, int arg2, int arg3);
|
||||
unsigned groups;
|
||||
int arg1;
|
||||
int arg2;
|
||||
int arg3;
|
||||
#if WITH_HELP
|
||||
const char *syntax;
|
||||
#endif
|
||||
} ;
|
||||
|
||||
#define XIO_WRITABLE(s) (((s)->common.flags+1)&2)
|
||||
#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]->fd:(s)->stream.fd)
|
||||
#define XIO_GETWRFD(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[1]->fd:(((s)->stream.dtype&XIODATA_WRITEMASK)==XIOWRITE_2PIPE)?(s)->stream.para.exec.fdout:(((s)->stream.dtype&XIODATA_WRITEMASK)==XIOWRITE_PIPE)?(s)->stream.para.bipipe.fdout:(s)->stream.fd)
|
||||
#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_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)
|
||||
|
||||
typedef unsigned long flags_t;
|
||||
|
@ -357,6 +556,12 @@ struct opt {
|
|||
union integral value;
|
||||
} ;
|
||||
|
||||
/* with threading, the arguments indirectly passed to xioengine() */
|
||||
struct threadarg_struct {
|
||||
xiofile_t *xfd1;
|
||||
xiofile_t *xfd2;
|
||||
} ;
|
||||
|
||||
extern const char *PIPESEP;
|
||||
extern xiofile_t *sock[XIO_MAXSOCK];
|
||||
|
||||
|
@ -372,33 +577,39 @@ extern xiofile_t *sock[XIO_MAXSOCK];
|
|||
#define STAT_NORETRY -3 /* address syntax error, not implemented etc;
|
||||
not even by external changes correctable */
|
||||
|
||||
extern int xioinitialize(void);
|
||||
extern int xioinitialize(int xioflags);
|
||||
extern int xio_forked_inchild(void);
|
||||
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 flags);
|
||||
extern int xioopensingle(char *addr, struct single *xfd, int xioflags);
|
||||
extern xiofile_t *xioopen(const char *args, int xioflags);
|
||||
extern xiofile_t *xioopenx(const char *addr, int xioflags, int infd, int outfd);extern int xiosocketpair(xiofile_t **xfd1p, xiofile_t **xfd2p, int how, ...);
|
||||
|
||||
extern int xioopensingle(char *addr, xiosingle_t *fd, int xioflags);
|
||||
extern int xioopenhelp(FILE *of, int level);
|
||||
|
||||
/* must be outside function for use by childdied handler */
|
||||
extern xiofile_t *sock1, *sock2;
|
||||
extern pid_t diedunknown1; /* child died before it is registered */
|
||||
extern pid_t diedunknown2;
|
||||
extern pid_t diedunknown3;
|
||||
extern pid_t diedunknown4;
|
||||
extern xiofile_t *xioallocfd(void);
|
||||
extern void xiofreefd(xiofile_t *xfd);
|
||||
|
||||
extern int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *));
|
||||
extern int xio_opt_signal(pid_t pid, int signum);
|
||||
extern void childdied(int signum);
|
||||
|
||||
extern void *xioengine(void *thread_arg);
|
||||
extern int _socat(xiofile_t *xfd1, xiofile_t *xfd2);
|
||||
extern ssize_t xioread(xiofile_t *sock1, void *buff, size_t bufsiz);
|
||||
extern ssize_t xiopending(xiofile_t *sock1);
|
||||
extern ssize_t xiowrite(xiofile_t *sock1, const void *buff, size_t bufsiz);
|
||||
extern int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
||||
unsigned char **buff, size_t bufsiz, bool righttoleft);
|
||||
extern int xioshutdown(xiofile_t *sock, int how);
|
||||
|
||||
extern int xioclose(xiofile_t *sock);
|
||||
extern void xioexit(void);
|
||||
|
||||
extern int (*xiohook_newchild)(void); /* xio calls this function from a new child process */
|
||||
extern int socat_sigchild(struct single *file);
|
||||
|
||||
|
||||
extern xioopts_t xioopts, *xioparams;
|
||||
|
||||
|
||||
#endif /* !defined(__xio_h_included) */
|
||||
|
|
81
xioclose.c
81
xioclose.c
|
@ -21,63 +21,82 @@ int xioclose1(struct single *pipe) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
switch (pipe->howtoclose) {
|
||||
|
||||
#if WITH_READLINE
|
||||
if ((pipe->dtype & XIODATA_MASK) == XIODATA_READLINE) {
|
||||
case XIOCLOSE_READLINE:
|
||||
Write_history(pipe->para.readline.history_file);
|
||||
/*xiotermios_setflag(pipe->fd, 3, ECHO|ICANON);*/ /* error when pty closed */
|
||||
}
|
||||
break;
|
||||
#endif /* WITH_READLINE */
|
||||
|
||||
#if WITH_OPENSSL
|
||||
if ((pipe->dtype & XIODATA_MASK) == XIODATA_OPENSSL) {
|
||||
case XIOCLOSE_OPENSSL:
|
||||
if (pipe->para.openssl.ssl) {
|
||||
/* e.g. on TCP connection refused, we do not yet have this set */
|
||||
sycSSL_shutdown(pipe->para.openssl.ssl);
|
||||
sycSSL_free(pipe->para.openssl.ssl);
|
||||
pipe->para.openssl.ssl = NULL;
|
||||
}
|
||||
Close(pipe->fd); pipe->fd = -1;
|
||||
Close(pipe->fd1); pipe->fd1 = -1;
|
||||
Close(pipe->fd2); pipe->fd2 = -1;
|
||||
if (pipe->para.openssl.ctx) {
|
||||
sycSSL_CTX_free(pipe->para.openssl.ctx);
|
||||
pipe->para.openssl.ctx = NULL;
|
||||
}
|
||||
} else
|
||||
break;
|
||||
#endif /* WITH_OPENSSL */
|
||||
|
||||
#if WITH_TERMIOS
|
||||
if (pipe->ttyvalid) {
|
||||
if (Tcsetattr(pipe->fd, 0, &pipe->savetty) < 0) {
|
||||
if (Tcsetattr(pipe->fd1, 0, &pipe->savetty) < 0) {
|
||||
Warn2("cannot restore terminal settings on fd %d: %s",
|
||||
pipe->fd, strerror(errno));
|
||||
pipe->fd1, strerror(errno));
|
||||
}
|
||||
}
|
||||
#endif /* WITH_TERMIOS */
|
||||
if (pipe->fd >= 0) {
|
||||
switch (pipe->howtoend) {
|
||||
case END_KILL: case END_SHUTDOWN_KILL: case END_CLOSE_KILL:
|
||||
if (pipe->para.exec.pid > 0) {
|
||||
if (Kill(pipe->para.exec.pid, SIGTERM) < 0) {
|
||||
|
||||
case XIOCLOSE_SIGTERM:
|
||||
if (pipe->child.pid > 0) {
|
||||
if (Kill(pipe->child.pid, SIGTERM) < 0) {
|
||||
Msg2(errno==ESRCH?E_INFO:E_WARN, "kill(%d, SIGTERM): %s",
|
||||
pipe->para.exec.pid, strerror(errno));
|
||||
pipe->child.pid, strerror(errno));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XIOCLOSE_CLOSE_SIGTERM:
|
||||
if (pipe->child.pid > 0) {
|
||||
if (Kill(pipe->child.pid, SIGTERM) < 0) {
|
||||
Msg2(errno==ESRCH?E_INFO:E_WARN, "kill(%d, SIGTERM): %s",
|
||||
pipe->child.pid, strerror(errno));
|
||||
}
|
||||
}
|
||||
/*PASSTHROUGH*/
|
||||
case XIOCLOSE_CLOSE:
|
||||
if (pipe->fd1 >= 0) {
|
||||
if (Close(pipe->fd1) < 0) {
|
||||
Info2("close(%d): %s", pipe->fd1, strerror(errno));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case XIOCLOSE_SLEEP_SIGTERM:
|
||||
Sleep(1);
|
||||
if (pipe->child.pid > 0) {
|
||||
if (Kill(pipe->child.pid, SIGTERM) < 0) {
|
||||
Msg2(errno==ESRCH?E_INFO:E_WARN, "kill(%d, SIGTERM): %s",
|
||||
pipe->child.pid, strerror(errno));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case XIOCLOSE_NONE:
|
||||
break;
|
||||
|
||||
default:
|
||||
Error2("xioclose(): bad end action 0x%x on 0x%x", pipe->howtoclose, pipe);
|
||||
break;
|
||||
}
|
||||
switch (pipe->howtoend) {
|
||||
case END_CLOSE: case END_CLOSE_KILL:
|
||||
if (Close(pipe->fd) < 0) {
|
||||
Info2("close(%d): %s", pipe->fd, strerror(errno)); } break;
|
||||
#if WITH_SOCKET
|
||||
case END_SHUTDOWN: case END_SHUTDOWN_KILL:
|
||||
if (Shutdown(pipe->fd, 2) < 0) {
|
||||
Info3("shutdown(%d, %d): %s", pipe->fd, 2, strerror(errno)); }
|
||||
break;
|
||||
#endif /* WITH_SOCKET */
|
||||
case END_UNLINK: if (Unlink((const char *)pipe->name) < 0) {
|
||||
Warn2("unlink(\"%s\"): %s", pipe->name, strerror(errno)); }
|
||||
break;
|
||||
case END_NONE: default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/* unlock */
|
||||
if (pipe->havelock) {
|
||||
|
@ -98,6 +117,7 @@ int xioclose1(struct single *pipe) {
|
|||
|
||||
/* close the xio fd */
|
||||
int xioclose(xiofile_t *file) {
|
||||
xiofile_t *xfd = file;
|
||||
int result;
|
||||
|
||||
if (file->tag == XIO_TAG_INVALID) {
|
||||
|
@ -113,6 +133,9 @@ int xioclose(xiofile_t *file) {
|
|||
} else {
|
||||
result = xioclose1(&file->stream);
|
||||
}
|
||||
if (xfd->stream.subthread != 0) {
|
||||
Pthread_join(xfd->stream.subthread, NULL);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
37
xioconfig.h
37
xioconfig.h
|
@ -21,33 +21,40 @@
|
|||
#endif
|
||||
|
||||
#if WITH_SOCKS4A
|
||||
# define WITH_SOCKS4 1
|
||||
# define _WITH_SOCKS4 1
|
||||
#endif
|
||||
|
||||
#if WITH_SOCKS4 || WITH_PROXY
|
||||
# define WITH_TCP 1
|
||||
# define WITH_IP4 1 /* currently this socks implementation does not work
|
||||
#if WITH_SOCKS4 || WITH_SOCKS5 || WITH_PROXY
|
||||
# define _WITH_TCP 1
|
||||
# define _WITH_IP4 1 /* currently this socks implementation does not work
|
||||
with IP6 */
|
||||
#endif
|
||||
|
||||
#if WITH_OPENSSL
|
||||
# define WITH_TCP 1
|
||||
# define WITH_IP4 1
|
||||
#endif
|
||||
|
||||
#if WITH_IP6
|
||||
#if 0
|
||||
#if !defined(HAVE_NETINET_IP6_H)
|
||||
# undef WITH_IP6
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if WITH_OPENSSL
|
||||
# define _WITH_TCP 1
|
||||
# define _WITH_IP4 1
|
||||
# if WITH_IP6
|
||||
# define _WITH_IP6 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !WITH_IP4 && !WITH_IP6
|
||||
# if WITH_TCP || WITH_UDP || WITH_RAWIP
|
||||
# define WITH_IP4 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if WITH_UNIX || WITH_IP4 || WITH_IP6 || WITH_SOCKS4 || WITH_RAWIP
|
||||
#if WITH_UNIX || HAVE_SYS_UN_H
|
||||
# define _WITH_UNIX 1
|
||||
#endif
|
||||
|
||||
#if WITH_IP4 || WITH_IP6 || WITH_SOCKS4 || WITH_RAWIP || _WITH_UNIX
|
||||
# define WITH_SOCKET 1
|
||||
#else
|
||||
# undef WITH_SOCKET
|
||||
|
@ -65,6 +72,14 @@
|
|||
# define _WITH_SOCKET 1
|
||||
#endif
|
||||
|
||||
#if WITH_TCP
|
||||
# define _WITH_TCP 1
|
||||
# define _WITH_IP4 1
|
||||
# if WITH_IP6
|
||||
# define _WITH_IP6 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if WITH_IP4 || WITH_TUN
|
||||
# define _WITH_IP4 1
|
||||
#endif
|
||||
|
|
434
xioengine.c
Normal file
434
xioengine.c
Normal file
|
@ -0,0 +1,434 @@
|
|||
/* $Id$ */
|
||||
/* Copyright Gerhard Rieger 2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this is the source file of the socat transfer loop/engine */
|
||||
|
||||
#include "xiosysincludes.h"
|
||||
|
||||
#include "xioopen.h"
|
||||
#include "xiosigchld.h"
|
||||
|
||||
|
||||
/* checks if this is a connection to a child process, and if so, sees if the
|
||||
child already died, leaving some data for us.
|
||||
returns <0 if an error occurred;
|
||||
returns 0 if no child or not yet died or died without data (sets eof);
|
||||
returns >0 if child died and left data
|
||||
*/
|
||||
int childleftdata(xiofile_t *xfd) {
|
||||
fd_set in, out, expt;
|
||||
int retval;
|
||||
/* have to check if a child process died before, but left read data */
|
||||
if (XIO_READABLE(xfd) &&
|
||||
(XIO_RDSTREAM(xfd)->howtoclose == XIOCLOSE_SIGTERM ||
|
||||
XIO_RDSTREAM(xfd)->howtoclose == XIOCLOSE_SIGKILL ||
|
||||
XIO_RDSTREAM(xfd)->howtoclose == XIOCLOSE_CLOSE_SIGTERM ||
|
||||
XIO_RDSTREAM(xfd)->howtoclose == XIOCLOSE_CLOSE_SIGKILL) &&
|
||||
XIO_RDSTREAM(xfd)->child.pid == 0) {
|
||||
struct timeval time0 = { 0,0 };
|
||||
|
||||
FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt);
|
||||
if (XIO_READABLE(xfd) && !(XIO_RDSTREAM(xfd)->eof >= 2 && !XIO_RDSTREAM(xfd)->ignoreeof)) {
|
||||
FD_SET(XIO_GETRDFD(xfd), &in);
|
||||
/*0 FD_SET(XIO_GETRDFD(xfd), &expt);*/
|
||||
}
|
||||
do {
|
||||
retval = Select(FD_SETSIZE, &in, &out, &expt, &time0);
|
||||
} while (retval < 0 && errno == EINTR);
|
||||
|
||||
if (retval < 0) {
|
||||
#if HAVE_FDS_BITS
|
||||
Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s",
|
||||
FD_SETSIZE, in.fds_bits[0], out.fds_bits[0],
|
||||
expt.fds_bits[0], strerror(errno));
|
||||
#else
|
||||
Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s",
|
||||
FD_SETSIZE, in.__fds_bits[0], out.__fds_bits[0],
|
||||
expt.__fds_bits[0], strerror(errno));
|
||||
#endif
|
||||
return -1;
|
||||
} else if (retval == 0) {
|
||||
Info("terminated child did not leave data for us");
|
||||
XIO_RDSTREAM(xfd)->eof = 2;
|
||||
xfd->stream.eof = 2;
|
||||
/*0 closing = MAX(closing, 1);*/
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *xioengine(void *thread_arg) {
|
||||
struct threadarg_struct *engine_arg = thread_arg;
|
||||
|
||||
_socat(engine_arg->xfd1, engine_arg->xfd2);
|
||||
free(engine_arg);
|
||||
return NULL/*!*/;
|
||||
}
|
||||
|
||||
/* here we come when the sockets are opened (in the meaning of C language),
|
||||
and their options are set/applied
|
||||
returns -1 on error or 0 on success */
|
||||
int _socat(xiofile_t *xfd1, xiofile_t *xfd2) {
|
||||
xiofile_t *sock1, *sock2;
|
||||
fd_set in, out, expt;
|
||||
int retval;
|
||||
unsigned char *buff;
|
||||
ssize_t bytes1, bytes2;
|
||||
int polling = 0; /* handling ignoreeof */
|
||||
int wasaction = 1; /* last select was active, do NOT sleep before next */
|
||||
struct timeval total_timeout; /* the actual total timeout timer */
|
||||
bool mayrd1 = false; /* sock1 has read data or eof, according to select() */
|
||||
bool mayrd2 = false; /* sock2 has read data or eof, according to select() */
|
||||
bool maywr1 = false; /* sock1 can be written to, according to select() */
|
||||
bool maywr2 = false; /* sock2 can be written to, according to select() */
|
||||
|
||||
sock1 = xfd1;
|
||||
sock2 = xfd2;
|
||||
|
||||
#if WITH_FILAN
|
||||
if (xioparams->debug) {
|
||||
int fdi, fdo;
|
||||
int msglevel, exitlevel;
|
||||
|
||||
msglevel = diag_get_int('D'); /* save current message level */
|
||||
diag_set_int('D', E_ERROR); /* only print errors and fatals in filan */
|
||||
exitlevel = diag_get_int('e'); /* save current exit level */
|
||||
diag_set_int('e', E_FATAL); /* only exit on fatals */
|
||||
|
||||
fdi = XIO_GETRDFD(sock1);
|
||||
fdo = XIO_GETWRFD(sock1);
|
||||
filan_fd(fdi, stderr);
|
||||
if (fdo != fdi) {
|
||||
filan_fd(fdo, stderr);
|
||||
}
|
||||
|
||||
fdi = XIO_GETRDFD(sock2);
|
||||
fdo = XIO_GETWRFD(sock2);
|
||||
filan_fd(fdi, stderr);
|
||||
if (fdo != fdi) {
|
||||
filan_fd(fdo, stderr);
|
||||
}
|
||||
|
||||
diag_set_int('e', exitlevel); /* restore old exit level */
|
||||
diag_set_int('D', msglevel); /* restore old message level */
|
||||
}
|
||||
#endif /* WITH_FILAN */
|
||||
|
||||
/* when converting nl to crnl, size might double */
|
||||
buff = Malloc(2*xioparams->bufsiz+1);
|
||||
if (buff == NULL) return -1;
|
||||
|
||||
if (xioparams->logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') {
|
||||
Info("switching to syslog");
|
||||
diag_set('y', xioopts.syslogfac);
|
||||
xiosetopt('l', "\0");
|
||||
}
|
||||
total_timeout = xioparams->total_timeout;
|
||||
|
||||
Notice4("starting data transfer loop with FDs [%d,%d] and [%d,%d]",
|
||||
XIO_GETRDFD(sock1), XIO_GETWRFD(sock1),
|
||||
XIO_GETRDFD(sock2), XIO_GETWRFD(sock2));
|
||||
while (XIO_RDSTREAM(sock1)->eof <= 1 ||
|
||||
XIO_RDSTREAM(sock2)->eof <= 1) {
|
||||
struct timeval timeout, *to = NULL;
|
||||
|
||||
Debug4("data loop: sock1->eof=%d, sock2->eof=%d, 1->closing=%d, 2->closing=%d",
|
||||
XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock2)->eof,
|
||||
sock1->stream.closing, sock2->stream.closing);
|
||||
Debug3("wasaction=%d, total_to={"F_tv_sec"."F_tv_usec"}",
|
||||
wasaction, total_timeout.tv_sec, total_timeout.tv_usec);
|
||||
|
||||
/* for ignoreeof */
|
||||
if (polling) {
|
||||
if (!wasaction) {
|
||||
/* yes we could do it with select but I like readable trace output */
|
||||
if (xioparams->pollintv.tv_sec) Sleep(xioparams->pollintv.tv_sec);
|
||||
if (xioparams->pollintv.tv_usec) Usleep(xioparams->pollintv.tv_usec);
|
||||
|
||||
if (xioparams->total_timeout.tv_sec != 0 ||
|
||||
xioparams->total_timeout.tv_usec != 0) {
|
||||
if (total_timeout.tv_usec < xioparams->pollintv.tv_usec) {
|
||||
total_timeout.tv_usec += 1000000;
|
||||
total_timeout.tv_sec -= 1;
|
||||
}
|
||||
total_timeout.tv_sec -= xioparams->pollintv.tv_sec;
|
||||
total_timeout.tv_usec -= xioparams->pollintv.tv_usec;
|
||||
if (total_timeout.tv_sec < 0 ||
|
||||
total_timeout.tv_sec == 0 && total_timeout.tv_usec < 0) {
|
||||
Notice("inactivity timeout triggered");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
wasaction = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (polling) {
|
||||
/* there is a ignoreeof poll timeout, use it */
|
||||
timeout = xioparams->pollintv;
|
||||
to = &timeout;
|
||||
} else if (xioparams->total_timeout.tv_sec != 0 ||
|
||||
xioparams->total_timeout.tv_usec != 0) {
|
||||
/* there might occur a total inactivity timeout */
|
||||
timeout = xioparams->total_timeout;
|
||||
to = &timeout;
|
||||
} else {
|
||||
to = NULL;
|
||||
}
|
||||
|
||||
#if 1
|
||||
if (sock1->stream.closing>=1 || sock2->stream.closing>=1) {
|
||||
/* first eof already occurred, start end timer */
|
||||
timeout = xioparams->closwait;
|
||||
to = &timeout;
|
||||
}
|
||||
#endif
|
||||
|
||||
do {
|
||||
int _errno;
|
||||
FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt);
|
||||
|
||||
childleftdata(sock1);
|
||||
childleftdata(sock2);
|
||||
|
||||
#if 0
|
||||
if (closing>=1) {
|
||||
/* first eof already occurred, start end timer */
|
||||
timeout = xioparams->closwait;
|
||||
to = &timeout;
|
||||
closing = 2;
|
||||
}
|
||||
#else
|
||||
if (sock1->stream.closing>=1 || sock2->stream.closing>=1) {
|
||||
/* first eof already occurred, start end timer */
|
||||
timeout = xioparams->closwait;
|
||||
to = &timeout;
|
||||
if (sock1->stream.closing==1) {
|
||||
sock1->stream.closing = 2;
|
||||
}
|
||||
if (sock2->stream.closing==1) {
|
||||
sock2->stream.closing = 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (XIO_READABLE(sock1) &&
|
||||
!(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof)
|
||||
/*0 && !xioparams->righttoleft*/) {
|
||||
Debug3("*** sock1: %p [%d,%d]", sock1, XIO_GETRDFD(sock1), XIO_GETWRFD(sock1));
|
||||
if (!mayrd1) {
|
||||
FD_SET(XIO_GETRDFD(sock1), &in);
|
||||
}
|
||||
if (!maywr2) {
|
||||
FD_SET(XIO_GETWRFD(sock2), &out);
|
||||
}
|
||||
}
|
||||
if (XIO_READABLE(sock2) &&
|
||||
!(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof)
|
||||
/*0 && !xioparams->lefttoright*/) {
|
||||
Debug3("*** sock2: %p [%d,%d]", sock2, XIO_GETRDFD(sock2), XIO_GETWRFD(sock2));
|
||||
if (!mayrd2) {
|
||||
FD_SET(XIO_GETRDFD(sock2), &in);
|
||||
}
|
||||
if (!maywr1) {
|
||||
FD_SET(XIO_GETWRFD(sock1), &out);
|
||||
}
|
||||
}
|
||||
retval = Select(FD_SETSIZE, &in, &out, &expt, to);
|
||||
_errno = errno;
|
||||
if (retval < 0 && errno == EINTR) {
|
||||
Info1("select(): %s", strerror(errno));
|
||||
}
|
||||
errno = _errno;
|
||||
} while (retval < 0 && errno == EINTR);
|
||||
|
||||
/* attention:
|
||||
when an exec'd process sends data and terminates, it is unpredictable
|
||||
whether the data or the sigchild arrives first.
|
||||
*/
|
||||
|
||||
if (retval < 0) {
|
||||
#if HAVE_FDS_BITS
|
||||
Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s",
|
||||
FD_SETSIZE, in.fds_bits[0], out.fds_bits[0],
|
||||
expt.fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0,
|
||||
strerror(errno));
|
||||
#else
|
||||
Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s",
|
||||
FD_SETSIZE, in.__fds_bits[0], out.__fds_bits[0],
|
||||
expt.__fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0,
|
||||
strerror(errno));
|
||||
#endif
|
||||
return -1;
|
||||
} else if (retval == 0) {
|
||||
Info2("select timed out (no data within %ld.%06ld seconds)",
|
||||
(sock1->stream.closing>=1||sock2->stream.closing>=1)?
|
||||
xioparams->closwait.tv_sec:xioparams->total_timeout.tv_sec,
|
||||
(sock1->stream.closing>=1||sock2->stream.closing>=1)?
|
||||
xioparams->closwait.tv_usec:xioparams->total_timeout.tv_usec);
|
||||
if (polling && !wasaction) {
|
||||
/* there was a ignoreeof poll timeout, use it */
|
||||
;
|
||||
} else if (xioparams->total_timeout.tv_sec != 0 ||
|
||||
xioparams->total_timeout.tv_usec != 0) {
|
||||
/* there was a total inactivity timeout */
|
||||
Notice("inactivity timeout triggered");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sock1->stream.closing || sock2->stream.closing) {
|
||||
break;
|
||||
}
|
||||
/* one possibility to come here is ignoreeof on some fd, but no EOF
|
||||
and no data on any descriptor - this is no indication for end! */
|
||||
continue;
|
||||
}
|
||||
|
||||
/*0 Debug1("XIO_READABLE(sock1) = %d", XIO_READABLE(sock1));*/
|
||||
/*0 Debug1("XIO_GETRDFD(sock1) = %d", XIO_GETRDFD(sock1));*/
|
||||
if (XIO_READABLE(sock1) && XIO_GETRDFD(sock1) >= 0 &&
|
||||
FD_ISSET(XIO_GETRDFD(sock1), &in)) {
|
||||
mayrd1 = true;
|
||||
}
|
||||
/*0 Debug1("XIO_READABLE(sock2) = %d", XIO_READABLE(sock2));*/
|
||||
/*0 Debug1("XIO_GETRDFD(sock2) = %d", XIO_GETRDFD(sock2));*/
|
||||
/*0 Debug1("FD_ISSET(XIO_GETRDFD(sock2), &in) = %d", FD_ISSET(XIO_GETRDFD(sock2), &in));*/
|
||||
if (XIO_READABLE(sock2) && XIO_GETRDFD(sock2) >= 0 &&
|
||||
FD_ISSET(XIO_GETRDFD(sock2), &in)) {
|
||||
mayrd2 = true;
|
||||
}
|
||||
/*0 Debug2("mayrd2 = %d, maywr1 = %d", mayrd2, maywr1);*/
|
||||
if (XIO_GETWRFD(sock1) >= 0 && FD_ISSET(XIO_GETWRFD(sock1), &out)) {
|
||||
maywr1 = true;
|
||||
}
|
||||
if (XIO_GETWRFD(sock2) >= 0 && FD_ISSET(XIO_GETWRFD(sock2), &out)) {
|
||||
maywr2 = true;
|
||||
}
|
||||
|
||||
if (mayrd1 && maywr2) {
|
||||
mayrd1 = false;
|
||||
if ((bytes1 = xiotransfer(sock1, sock2, &buff, xioparams->bufsiz, false))
|
||||
< 0) {
|
||||
if (errno != EAGAIN) {
|
||||
/*sock2->closing = MAX(socks2->closing, 1);*/
|
||||
Notice("socket 1 to socket 2 is in error");
|
||||
if (/*0 xioparams->lefttoright*/ !XIO_READABLE(sock2)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (bytes1 > 0) {
|
||||
maywr2 = false;
|
||||
total_timeout = xioparams->total_timeout;
|
||||
wasaction = 1;
|
||||
/* is more data available that has already passed select()? */
|
||||
mayrd1 = (xiopending(sock1) > 0);
|
||||
if (XIO_RDSTREAM(sock1)->readbytes != 0 &&
|
||||
XIO_RDSTREAM(sock1)->actbytes == 0) {
|
||||
/* avoid idle when all readbytes already there */
|
||||
mayrd1 = true;
|
||||
}
|
||||
} else { /* bytes1 == 0 */
|
||||
if (XIO_RDSTREAM(sock1)->ignoreeof && !sock1->stream.closing) {
|
||||
;
|
||||
} else {
|
||||
XIO_RDSTREAM(sock1)->eof = 2;
|
||||
}
|
||||
/* (bytes1 == 0) handled later */
|
||||
}
|
||||
} else {
|
||||
bytes1 = -1;
|
||||
}
|
||||
|
||||
if (mayrd2 && maywr1) {
|
||||
mayrd2 = false;
|
||||
if ((bytes2 = xiotransfer(sock2, sock1, &buff, xioparams->bufsiz, true))
|
||||
< 0) {
|
||||
if (errno != EAGAIN) {
|
||||
/*sock1->closing = MAX(sock1->closing, 1);*/
|
||||
Notice("socket 2 to socket 1 is in error");
|
||||
if (/*0 xioparams->righttoleft*/ !XIO_READABLE(sock1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (bytes2 > 0) {
|
||||
maywr1 = false;
|
||||
total_timeout = xioparams->total_timeout;
|
||||
wasaction = 1;
|
||||
/* is more data available that has already passed select()? */
|
||||
mayrd2 = (xiopending(sock2) > 0);
|
||||
if (XIO_RDSTREAM(sock2)->readbytes != 0 &&
|
||||
XIO_RDSTREAM(sock2)->actbytes == 0) {
|
||||
/* avoid idle when all readbytes already there */
|
||||
mayrd2 = true;
|
||||
}
|
||||
} else { /* bytes == 0 */
|
||||
if (XIO_RDSTREAM(sock2)->ignoreeof && !sock2->stream.closing) {
|
||||
;
|
||||
} else {
|
||||
XIO_RDSTREAM(sock2)->eof = 2;
|
||||
}
|
||||
/* (bytes2 == 0) handled later */
|
||||
}
|
||||
} else {
|
||||
bytes2 = -1;
|
||||
}
|
||||
|
||||
/* NOW handle EOFs */
|
||||
|
||||
if (bytes1 == 0 || XIO_RDSTREAM(sock1)->eof >= 2) {
|
||||
if (XIO_RDSTREAM(sock1)->ignoreeof && !sock1->stream.closing) {
|
||||
Debug1("socket 1 (fd %d) is at EOF, ignoring",
|
||||
XIO_RDSTREAM(sock1)->fd1); /*! */
|
||||
polling = 1;
|
||||
} else {
|
||||
Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1));
|
||||
xioshutdown(sock2, SHUT_WR);
|
||||
sock2->stream.closing = MAX(sock2->stream.closing, 1);
|
||||
if (/*0 xioparams->lefttoright*/ !XIO_READABLE(sock2)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes2 == 0 || XIO_RDSTREAM(sock2)->eof >= 2) {
|
||||
if (XIO_RDSTREAM(sock2)->ignoreeof && !sock2->stream.closing) {
|
||||
Debug1("socket 2 (fd %d) is at EOF, ignoring",
|
||||
XIO_RDSTREAM(sock2)->fd1);
|
||||
polling = 1;
|
||||
} else {
|
||||
Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2));
|
||||
xioshutdown(sock1, SHUT_WR);
|
||||
sock1->stream.closing = MAX(sock1->stream.closing, 1);
|
||||
if (/*0 xioparams->righttoleft*/ !XIO_READABLE(sock1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* close everything that's still open */
|
||||
xioclose(sock1);
|
||||
xioclose(sock2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* this is the callback when the child of an address died */
|
||||
int socat_sigchild(struct single *file) {
|
||||
Debug3("socat_sigchild().1: file->ignoreeof=%d, file->closing=%d, file->eof=%d",
|
||||
file->ignoreeof, file->closing, file->eof);
|
||||
if (file->ignoreeof && !file->closing) {
|
||||
;
|
||||
} else {
|
||||
file->eof = MAX(file->eof, 1);
|
||||
file->closing = 3;
|
||||
}
|
||||
Debug3("socat_sigchild().9: file->ignoreeof=%d, file->closing=%d, file->eof=%d",
|
||||
file->ignoreeof, file->closing, file->eof);
|
||||
return 0;
|
||||
}
|
60
xiohelp.c
60
xiohelp.c
|
@ -41,7 +41,7 @@ static const char *addressgroupnames[] = {
|
|||
"TERMIOS", "RANGE", "PTY", "PARENT",
|
||||
"UNIX", "IP4", "IP6", "INTERFACE",
|
||||
"UDP", "TCP", "SOCKS4", "OPENSSL",
|
||||
"PROCESS", "APPL", "HTTP", "undef"
|
||||
"PROCESS", "APPL", "HTTP", "SOCKS5"
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -89,7 +89,7 @@ static int xiohelp_option(FILE *of, const struct optname *on, const char *name)
|
|||
int xioopenhelp(FILE *of,
|
||||
int level /* 0..only addresses, 1..and options */
|
||||
) {
|
||||
const struct addrname *an;
|
||||
const struct xioaddrname *an;
|
||||
const struct optname *on;
|
||||
int i, j;
|
||||
unsigned int groups;
|
||||
|
@ -101,32 +101,68 @@ int xioopenhelp(FILE *of,
|
|||
fputs(" echo is an alias for pipe\n", of);
|
||||
fputs(" fifo is an alias for pipe\n", of);
|
||||
}
|
||||
fputs(" <single-address>!!<single-address>\n", of);
|
||||
fputs(" <single-address>%<single-address>\n", of);
|
||||
fputs(" <single-address>\n", of);
|
||||
fputs(" single-address:\n", of);
|
||||
fputs(" <address-head>[,<opts>]\n", of);
|
||||
fputs(" address-head:\n", of);
|
||||
an = &addressnames[0];
|
||||
an = &address_names[0];
|
||||
i = 0;
|
||||
while (addressnames[i].name) {
|
||||
if (!strcmp(an->name, an->desc->defname)) {
|
||||
while (address_names[i].name) {
|
||||
if (!strcmp(an->name, (an->desc)[0]->common_desc.defname)) {
|
||||
/* it is a canonical address name */
|
||||
fprintf(of, " %s", an->name);
|
||||
if (an->desc->syntax) {
|
||||
fputs(an->desc->syntax, of); }
|
||||
fputs("\tgroups=", of);
|
||||
groups = an->desc->groups; occurred = false;
|
||||
const union xioaddr_desc **ad;
|
||||
ad = an->desc;
|
||||
while (*ad != NULL) {
|
||||
const char *syntax;
|
||||
int pos = 0;
|
||||
fprintf(of, " %s", an->name); pos += strlen(an->name);
|
||||
if ((*ad)->tag == XIOADDR_ENDPOINT) {
|
||||
syntax = (*ad)->endpoint_desc.syntax;
|
||||
} else if ((*ad)->tag == XIOADDR_INTER) {
|
||||
syntax = (*ad)->inter_desc.syntax;
|
||||
} else {
|
||||
syntax = NULL;
|
||||
}
|
||||
if (syntax) {
|
||||
fputs(syntax, of); pos += strlen(syntax); }
|
||||
while (pos < 36) { putc(' ', of); ++pos; }
|
||||
if ((*ad)->common_desc.leftdirs & XIOBIT_RDONLY) {
|
||||
putc('r', of); } else { putc(' ', of); }
|
||||
if ((*ad)->common_desc.leftdirs & XIOBIT_WRONLY) {
|
||||
putc('w', of); } else { putc(' ', of); }
|
||||
if ((*ad)->common_desc.leftdirs & XIOBIT_RDWR) {
|
||||
putc('b', of); } else { putc(' ', of); }
|
||||
putc(' ', of);
|
||||
if ((*ad)->tag == 1) {
|
||||
while (pos < 36) { putc(' ', of); ++pos; }
|
||||
if ((*ad)->inter_desc.rightdirs & XIOBIT_RDONLY) {
|
||||
putc('r', of); } else { putc(' ', of); }
|
||||
if ((*ad)->inter_desc.rightdirs & XIOBIT_WRONLY) {
|
||||
putc('w', of); } else { putc(' ', of); }
|
||||
if ((*ad)->inter_desc.rightdirs & XIOBIT_RDWR) {
|
||||
putc('b', of); } else { putc(' ', of); }
|
||||
} else {
|
||||
fputs(" ", of);
|
||||
}
|
||||
|
||||
pos += 7;
|
||||
fputs(" groups=", of);
|
||||
groups = (*ad)->common_desc.groups; occurred = false;
|
||||
for (j = 0; j < 32; ++j) {
|
||||
if (groups & 1) {
|
||||
if (occurred) { fputc(',', of); }
|
||||
fprintf(of, "%s", addressgroupnames[j]);
|
||||
pos += strlen(addressgroupnames[j]);
|
||||
occurred = true;
|
||||
}
|
||||
groups >>= 1;
|
||||
}
|
||||
fputc('\n', of);
|
||||
++ad;
|
||||
}
|
||||
} else if (level == 2) {
|
||||
fprintf(of, " %s is an alias name for %s\n", an->name, an->desc->defname);
|
||||
fprintf(of, " %s is an alias name for %s\n", an->name, (an->desc)[0]->common_desc.defname);
|
||||
}
|
||||
++an; ++i;
|
||||
}
|
||||
|
|
|
@ -1,24 +1,30 @@
|
|||
/* $Id: xioinitialize.c,v 1.17 2006/12/28 14:21:41 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for the initialize function */
|
||||
|
||||
#include "xiosysincludes.h"
|
||||
|
||||
#include "xiostatic.h"
|
||||
#include "xioopen.h"
|
||||
#include "xiolockfile.h"
|
||||
#include "xiosigchld.h"
|
||||
|
||||
#include "xio-openssl.h" /* xio_reset_fips_mode() */
|
||||
|
||||
static int xioinitialized;
|
||||
xiofile_t *sock[XIO_MAXSOCK];
|
||||
int (*xiohook_newchild)(void); /* xio calls this function from a new child
|
||||
int (*xiohook_newchild)(void); /* xio calls this function in every new child
|
||||
process */
|
||||
|
||||
|
||||
/* call this function before calling any other xio function.
|
||||
With xioflags, you have to set the features that xio can make use of.
|
||||
Use XIO_MAYALL for unrestricted use. */
|
||||
/* returns 0 on success or != if an error occurred */
|
||||
int xioinitialize(void) {
|
||||
int xioinitialize(int xioflags) {
|
||||
int xio_flags;
|
||||
if (xioinitialized) return 0;
|
||||
|
||||
/* configure and .h's cannot guarantee this */
|
||||
|
@ -67,7 +73,7 @@ int xioinitialize(void) {
|
|||
assert(tdata.termarg.c_ospeed == tdata.speeds[OSPEED_OFFSET]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif /* WITH_TERMIOS */
|
||||
|
||||
/* these dependencies required in applyopts() for OFUNC_FCNTL */
|
||||
assert(F_GETFD == F_SETFD-1);
|
||||
|
@ -103,15 +109,41 @@ int xioinitialize(void) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
xio_flags = xioflags;
|
||||
|
||||
if ((xio_flags|XIO_MAYFORK) || (xio_flags|XIO_MAYCHILD) ||
|
||||
(xio_flags|XIO_MAYCHAIN)) {
|
||||
|
||||
#if HAVE_SIGACTION
|
||||
struct sigaction act;
|
||||
memset(&act, 0, sizeof(struct sigaction));
|
||||
act.sa_flags = SA_NOCLDSTOP|SA_RESTART|SA_SIGINFO
|
||||
#ifdef SA_NOMASK
|
||||
|SA_NOMASK
|
||||
#endif
|
||||
;
|
||||
act.sa_sigaction = childdied;
|
||||
if (Sigaction(SIGCHLD, &act, NULL) < 0) {
|
||||
/*! Linux man does not explicitely say that errno is defined */
|
||||
Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied, strerror(errno));
|
||||
}
|
||||
#else /* !HAVE_SIGACTION */
|
||||
act.sa_handler = childdied;
|
||||
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
|
||||
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
|
||||
}
|
||||
#endif /* !HAVE_SIGACTION */
|
||||
}
|
||||
|
||||
xioinitialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* well, this function is not for initialization, but I could not find a better
|
||||
place for it
|
||||
source file for it
|
||||
it is called in the child process after fork
|
||||
it drops the locks of the xiofile's so only the parent owns them
|
||||
it drops the lock references of the xiofile's so only the parent owns them
|
||||
*/
|
||||
void xiodroplocks(void) {
|
||||
int i;
|
||||
|
@ -124,6 +156,7 @@ void xiodroplocks(void) {
|
|||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/* consider an invokation like this:
|
||||
socat -u exec:'some program that accepts data' tcp-l:...,fork
|
||||
we do not want the program to be killed by the first tcp-l sub process, it's
|
||||
|
@ -146,16 +179,17 @@ static int xio_nokill(xiofile_t *sock) {
|
|||
case XIO_TAG_WRONLY:
|
||||
case XIO_TAG_RDWR:
|
||||
/* here is the core of this function */
|
||||
switch (sock->stream.howtoend) {
|
||||
case END_SHUTDOWN_KILL: sock->stream.howtoend = END_CLOSE; break;
|
||||
case END_CLOSE_KILL: sock->stream.howtoend = END_CLOSE; break;
|
||||
case END_SHUTDOWN: sock->stream.howtoend = END_CLOSE; break;
|
||||
switch (sock->stream.howtoclose) {
|
||||
case END_SHUTDOWN_KILL: sock->stream.howtoclose = END_CLOSE; break;
|
||||
case END_CLOSE_KILL: sock->stream.howtoclose = END_CLOSE; break;
|
||||
case END_SHUTDOWN: sock->stream.howtoclose = END_CLOSE; break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
/* call this function immediately after fork() in child process */
|
||||
/* it performs some neccessary actions
|
||||
|
@ -175,6 +209,7 @@ int xio_forked_inchild(void) {
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */
|
||||
if (sock1 != NULL) {
|
||||
int result2;
|
||||
|
@ -182,6 +217,7 @@ int xio_forked_inchild(void) {
|
|||
if (result2 < 0) Exit(1);
|
||||
result |= result2;
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xiolayer.c,v 1.7 2005/08/18 19:56:05 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2005 */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for common options */
|
||||
|
@ -18,8 +18,8 @@ const struct optdesc opt_lockfile = { "lockfile", NULL, OPT_LOCKFILE, GROUP_A
|
|||
const struct optdesc opt_waitlock = { "waitlock", NULL, OPT_WAITLOCK, GROUP_APPL, PH_INIT, TYPE_FILENAME, OFUNC_EXT, 0, 0 };
|
||||
/****** APPL addresses ******/
|
||||
#if WITH_RETRY
|
||||
const struct optdesc opt_forever = { "forever", NULL, OPT_FOREVER, GROUP_RETRY, PH_INIT, TYPE_BOOL, OFUNC_EXT, (int)(&((struct single *)0)->forever), sizeof(((struct single *)0)->forever) };
|
||||
const struct optdesc opt_intervall = { "intervall", NULL, OPT_INTERVALL, GROUP_RETRY, PH_INIT, TYPE_TIMESPEC, OFUNC_EXT, (int)(&((struct single *)0)->intervall), sizeof(((struct single *)0)->intervall) };
|
||||
const struct optdesc opt_retry = { "retry", NULL, OPT_RETRY, GROUP_RETRY, PH_INIT, TYPE_UINT, OFUNC_EXT, (int)(&((struct single *)0)->retry), sizeof(((struct single *)0)->retry) };
|
||||
const struct optdesc opt_forever = { "forever", NULL, OPT_FOREVER, GROUP_RETRY, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (int)(&((struct single *)0)->forever), sizeof(((struct single *)0)->forever) };
|
||||
const struct optdesc opt_intervall = { "intervall", NULL, OPT_INTERVALL, GROUP_RETRY, PH_INIT, TYPE_TIMESPEC, OFUNC_OFFSET, (int)(&((struct single *)0)->intervall), sizeof(((struct single *)0)->intervall) };
|
||||
const struct optdesc opt_retry = { "retry", NULL, OPT_RETRY, GROUP_RETRY, PH_INIT, TYPE_UINT, OFUNC_OFFSET, (int)(&((struct single *)0)->retry), sizeof(((struct single *)0)->retry) };
|
||||
#endif
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "xio-tcp.h"
|
||||
#include "xio-udp.h"
|
||||
#include "xio-socks.h"
|
||||
#include "xio-socks5.h"
|
||||
#include "xio-proxy.h"
|
||||
#endif /* WITH_SOCKET */
|
||||
#include "xio-progcall.h"
|
||||
|
@ -41,5 +42,7 @@
|
|||
#include "xio-tcpwrap.h"
|
||||
#include "xio-ext2.h"
|
||||
#include "xio-tun.h"
|
||||
#include "xio-nop.h"
|
||||
#include "xio-test.h"
|
||||
|
||||
#endif /* !defined(__xiomodes_h_included) */
|
||||
|
|
19
xioopen.h
19
xioopen.h
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xioopen.h,v 1.22 2006/05/12 20:14:05 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* $Id: xioopen.h,v 1.22.2.1 2006/07/24 19:26:29 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xioopen_h_included
|
||||
|
@ -33,16 +33,25 @@ extern const struct optdesc opt_tabdly;
|
|||
extern const struct optdesc opt_csize;
|
||||
|
||||
|
||||
struct addrname {
|
||||
struct xioaddrname {
|
||||
const char *name;
|
||||
const struct addrdesc *desc;
|
||||
const union xioaddr_desc **desc;
|
||||
} ;
|
||||
|
||||
struct xioaddr_endpoint_name {
|
||||
const char *name;
|
||||
const struct xioaddr_endpoint_desc **desc;
|
||||
} ;
|
||||
|
||||
extern const char *ddirection[];
|
||||
extern const char *filetypenames[];
|
||||
extern const struct addrname addressnames[];
|
||||
extern const struct xioaddrname address_names[];
|
||||
extern const struct optname optionnames[];
|
||||
|
||||
extern xiofile_t *socat_open(const char *addrs0, int dirs, int flags);
|
||||
extern xiofile_t *xioparse_dual(const char **addr);
|
||||
extern int xioopen_inter_dual(xiofile_t *xfd, int xioflags);
|
||||
extern int xioopen_endpoint_dual(xiofile_t *xfd, int xioflags);
|
||||
extern int xioopen_makedual(xiofile_t *file);
|
||||
|
||||
#define retropt_2bytes(o,c,r) retropt_ushort(o,c,r)
|
||||
|
|
96
xioopts.c
96
xioopts.c
|
@ -88,6 +88,12 @@ bool xioopts_ignoregroups;
|
|||
# define IF_SOCKS4(a,b)
|
||||
#endif
|
||||
|
||||
#if WITH_SOCKS5
|
||||
# define IF_SOCKS5(a,b) {a,b},
|
||||
#else
|
||||
# define IF_SOCKS5(a,b)
|
||||
#endif
|
||||
|
||||
#if WITH_PROXY
|
||||
# define IF_PROXY(a,b) {a,b},
|
||||
#else
|
||||
|
@ -1190,6 +1196,7 @@ const struct optname optionnames[] = {
|
|||
#endif
|
||||
IF_ANY ("setuid", &opt_setuid)
|
||||
IF_ANY ("setuid-early", &opt_setuid_early)
|
||||
IF_ANY ("shut-none", &opt_shut_none)
|
||||
#if WITH_EXEC || WITH_SYSTEM
|
||||
IF_ANY ("sid", &opt_setsid)
|
||||
#endif
|
||||
|
@ -1302,6 +1309,8 @@ const struct optname optionnames[] = {
|
|||
#ifdef SO_USELOOPBACK /* AIX433, Solaris */
|
||||
IF_SOCKET ("so-useloopback", &opt_so_useloopback)
|
||||
#endif /* SO_USELOOPBACK */
|
||||
IF_SOCKS5 ("socks5-password", &opt_socks5_password)
|
||||
IF_SOCKS5 ("socks5-username", &opt_socks5_username)
|
||||
IF_SOCKS4 ("socksport", &opt_socksport)
|
||||
IF_SOCKS4 ("socksuser", &opt_socksuser)
|
||||
IF_IPAPP ("sourceport", &opt_sourceport)
|
||||
|
@ -1560,9 +1569,9 @@ const struct optname optionnames[] = {
|
|||
to the array opts. Uses the option table 'optionnames'.
|
||||
returns 0 on success, -1 on error, 1 on unknown/wrong option
|
||||
*/
|
||||
int parseopts(const char **a, unsigned int groups, struct opt **opts) {
|
||||
int parseopts(const char **a, struct opt **opts) {
|
||||
|
||||
return parseopts_table(a, groups, opts, optionnames,
|
||||
return parseopts_table(a, opts, optionnames,
|
||||
sizeof(optionnames)/sizeof(struct optname)-1);
|
||||
}
|
||||
|
||||
|
@ -1571,7 +1580,7 @@ int parseopts(const char **a, unsigned int groups, struct opt **opts) {
|
|||
to the array opts. Uses the specified option table.
|
||||
returns 0 on success, -1 on error, 1 on unknown/wrong option
|
||||
*/
|
||||
int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
||||
int parseopts_table(const char **a, struct opt **opts,
|
||||
const struct optname optionnames[], size_t optionnum) {
|
||||
int i=0;
|
||||
struct opt *opt;
|
||||
|
@ -1603,15 +1612,15 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
} ;
|
||||
|
||||
i = 0;
|
||||
/*endkey[i++] = xioopts.chainsep;*/ /* default: "|" */
|
||||
endkey[i++] = xioopts.pipesep; /* default: "!!" */
|
||||
endkey[i++] = xioopts.chainsep; /* default: "|" */
|
||||
endkey[i++] = xioopts.pipesep; /* default: "%" */
|
||||
endkey[i++] = ","/*xioopts.comma*/; /* default: "," */
|
||||
endkey[i++] = "=";
|
||||
endkey[i++] = NULL;
|
||||
|
||||
i = 0;
|
||||
/*endval[i++] = xioopts.chainsep;*/ /* default: "|" */
|
||||
endval[i++] = xioopts.pipesep; /* default: "!!" */
|
||||
endval[i++] = xioopts.chainsep; /* default: "|" */
|
||||
endval[i++] = xioopts.pipesep; /* default: "%" */
|
||||
endval[i++] = ","/*xioopts.comma*/; /* default: "," */
|
||||
endval[i++] = NULL;
|
||||
|
||||
|
@ -1637,7 +1646,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
len = sizeof(token); tokp = token;
|
||||
parsres =
|
||||
nestlex(a, &tokp, &len, endkey, hquotes, squotes, nests,
|
||||
true, true, false);
|
||||
true, true, true, false);
|
||||
if (parsres != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -1654,6 +1663,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
continue;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!(ent->desc->group & groups) && !(ent->desc->group & GROUP_ANY) &&
|
||||
!xioopts_ignoregroups) {
|
||||
Error1("parseopts(): option \"%s\" not supported with this address type",
|
||||
|
@ -1664,6 +1674,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
continue;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
(*opts)[i].desc = ent->desc;
|
||||
|
||||
if (!strncmp(*a, assign_str, strlen(assign_str))) {
|
||||
|
@ -1672,7 +1683,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
len = sizeof(token); tokp = token;
|
||||
parsres =
|
||||
nestlex(a, &tokp, &len, endval, hquotes, squotes, nests,
|
||||
true, true, false);
|
||||
true, true, true, false);
|
||||
if (parsres != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -1981,7 +1992,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
/*! result= */
|
||||
nestlex((const char **)&tokp, &buffp, &bufspc,
|
||||
ends, NULL, NULL, nests,
|
||||
true, false, false);
|
||||
true, true, false, false);
|
||||
if (*tokp != ':') {
|
||||
Error1("syntax in option %s: missing ':'", token);
|
||||
}
|
||||
|
@ -1994,7 +2005,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
/*! result= */
|
||||
nestlex((const char **)&tokp, &buffp, &bufspc,
|
||||
ends, NULL, NULL, nests,
|
||||
true, false, false);
|
||||
true, true, false, false);
|
||||
*buffp++ = '\0';
|
||||
(*opts)[i].value.u_ip_mreq.param2 = strdup(buff); /*!!! NULL */
|
||||
|
||||
|
@ -2034,7 +2045,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
tokp = token;
|
||||
nestlex((const char **)&tokp, &buffp, &bufspc,
|
||||
ends, NULL, NULL, nests,
|
||||
true, false, false);
|
||||
true, true, false, false);
|
||||
if (*tokp != '\0') {
|
||||
Error1("trailing data in option \"%s\"", token);
|
||||
}
|
||||
|
@ -2069,6 +2080,32 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* checks if the options conform to the group set.
|
||||
returns 0 if all options conform to the group set,
|
||||
or -1 otherwise. */
|
||||
int xiocheckopts(struct opt *opts, unsigned int groups) {
|
||||
const struct opt *opt = opts;
|
||||
|
||||
if (opts == NULL) {
|
||||
return 0;
|
||||
}
|
||||
while (opt->desc != ODESC_END) {
|
||||
|
||||
if (!(opt->desc->group & groups) &&
|
||||
!(opt->desc->group & GROUP_ANY) &&
|
||||
!xioopts_ignoregroups) {
|
||||
Error1("option \"%s\" not supported with this address type",
|
||||
opt->desc->defname);
|
||||
Info2("parseopts() groups=%08x, opt->group=%08x",
|
||||
groups, opt->desc->group);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* copy the already parsed options for repeated application, but only those
|
||||
matching groups ANY and <groups> */
|
||||
struct opt *copyopts(const struct opt *opts, unsigned int groups) {
|
||||
|
@ -2479,7 +2516,7 @@ int retropt_bind(struct opt *opts,
|
|||
portallowed = (feats>=2);
|
||||
bindp = bindname;
|
||||
nestlex((const char **)&bindp, &hostp, &hostlen, ends, NULL, NULL, nests,
|
||||
true, false, false);
|
||||
true, true, false, false);
|
||||
*hostp++ = '\0';
|
||||
if (!strncmp(bindp, portsep, strlen(portsep))) {
|
||||
if (!portallowed) {
|
||||
|
@ -2591,7 +2628,8 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) {
|
|||
long mask = opt->desc->arg3;
|
||||
|
||||
if (Ioctl(fd, getreq, (void *)&val) < 0) {
|
||||
Error4("ioctl(%d, 0x%x, %p): %s",
|
||||
Error5("option \"%s\": ioctl(%d, 0x%x, %p): %s",
|
||||
opt->desc->defname,
|
||||
fd, opt->desc->major, (void *)&val, strerror(errno));
|
||||
opt->desc = ODESC_ERROR; ++opt; continue;
|
||||
}
|
||||
|
@ -3339,6 +3377,8 @@ static int applyopt_offset(struct single *xfd, struct opt *opt) {
|
|||
switch (opt->desc->type) {
|
||||
case TYPE_BOOL:
|
||||
*(bool *)ptr = opt->value.u_bool; break;
|
||||
case TYPE_UINT:
|
||||
*(unsigned int *)ptr = opt->value.u_uint; break;
|
||||
case TYPE_DOUBLE:
|
||||
*(double *)ptr = opt->value.u_double; break;
|
||||
case TYPE_TIMEVAL:
|
||||
|
@ -3358,6 +3398,8 @@ static int applyopt_offset(struct single *xfd, struct opt *opt) {
|
|||
case TYPE_CONST:
|
||||
*(int *)ptr = opt->desc->minor;
|
||||
break;
|
||||
case TYPE_TIMESPEC:
|
||||
*(struct timespec *)ptr = opt->value.u_timespec; break;
|
||||
default:
|
||||
Error1("applyopt_offset(): type %d not implemented",
|
||||
opt->desc->type);
|
||||
|
@ -3574,10 +3616,10 @@ mc:addr
|
|||
#endif
|
||||
|
||||
#if HAVE_STRUCT_IP_MREQN
|
||||
if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor,
|
||||
if (Setsockopt(xfd->fd1, 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->fd, opt->desc->major, opt->desc->minor,
|
||||
xfd->fd1, 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,
|
||||
|
@ -3586,10 +3628,10 @@ mc:addr
|
|||
opt->desc = ODESC_ERROR; continue;
|
||||
}
|
||||
#else
|
||||
if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor,
|
||||
if (Setsockopt(xfd->fd1, opt->desc->major, opt->desc->minor,
|
||||
&ip4_mreqn.mreq, sizeof(ip4_mreqn.mreq)) < 0) {
|
||||
Error7("setsockopt(%d, %d, %d, {0x%08x,0x%08x}, "F_Zu"): %s",
|
||||
xfd->fd, opt->desc->major, opt->desc->minor,
|
||||
xfd->fd1, opt->desc->major, opt->desc->minor,
|
||||
ip4_mreqn.mreq.imr_multiaddr,
|
||||
ip4_mreqn.mreq.imr_interface,
|
||||
sizeof(ip4_mreqn.mreq),
|
||||
|
@ -3626,10 +3668,10 @@ mc:addr
|
|||
ip6_mreq.ipv6mr_interface = htonl(0);
|
||||
}
|
||||
|
||||
if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor,
|
||||
if (Setsockopt(xfd->fd1, opt->desc->major, opt->desc->minor,
|
||||
&ip6_mreq, sizeof(ip6_mreq)) < 0) {
|
||||
Error6("setsockopt(%d, %d, %d, {...,0x%08x}, "F_Zu"): %s",
|
||||
xfd->fd, opt->desc->major, opt->desc->minor,
|
||||
xfd->fd1, opt->desc->major, opt->desc->minor,
|
||||
ip6_mreq.ipv6mr_interface,
|
||||
sizeof(ip6_mreq),
|
||||
strerror(errno));
|
||||
|
@ -3668,7 +3710,7 @@ int applyopts_signal(struct single *xfd, struct opt *opts) {
|
|||
++opt; continue;
|
||||
}
|
||||
|
||||
if (xio_opt_signal(xfd->para.exec.pid, opt->desc->major) < 0) {
|
||||
if (xio_opt_signal(xfd->child.pid, opt->desc->major) < 0) {
|
||||
opt->desc = ODESC_ERROR; continue;
|
||||
}
|
||||
opt->desc = ODESC_DONE;
|
||||
|
@ -3685,15 +3727,23 @@ int _xio_openlate(struct single *fd, struct opt *opts) {
|
|||
|
||||
_xioopen_setdelayeduser();
|
||||
|
||||
if ((result = applyopts(fd->fd, opts, PH_LATE)) < 0) {
|
||||
if ((result = applyopts(fd->fd1, 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) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if ((result = applyopts_single(fd, opts, PH_LATE)) < 0) {
|
||||
return result;
|
||||
}
|
||||
if ((result = applyopts(fd->fd, opts, PH_LATE2)) < 0) {
|
||||
if ((result = applyopts(fd->fd1, opts, PH_LATE2)) < 0) {
|
||||
return result;
|
||||
}
|
||||
/*! need to apply to fd2 too! */
|
||||
|
||||
if ((numleft = leftopts(opts)) > 0) {
|
||||
showleft(opts);
|
||||
|
|
10
xioopts.h
10
xioopts.h
|
@ -145,6 +145,7 @@ enum e_func {
|
|||
#define GROUP_PROCESS 0x10000000 /* a process related option */
|
||||
#define GROUP_APPL 0x20000000 /* option handled by data loop */
|
||||
#define GROUP_HTTP 0x40000000 /* any HTTP client */
|
||||
#define GROUP_SOCKS5 0x80000000
|
||||
|
||||
#define GROUP_ANY (GROUP_PROCESS|GROUP_APPL)
|
||||
#define GROUP_ALL 0xffffffff
|
||||
|
@ -533,6 +534,7 @@ enum e_optcode {
|
|||
OPT_SETSID,
|
||||
OPT_SETUID,
|
||||
OPT_SETUID_EARLY,
|
||||
OPT_SHUT_NONE,
|
||||
OPT_SIGHUP,
|
||||
OPT_SIGINT,
|
||||
OPT_SIGQUIT,
|
||||
|
@ -630,6 +632,8 @@ enum e_optcode {
|
|||
#ifdef SO_USE_IFBUFS
|
||||
OPT_SO_USE_IFBUFS,
|
||||
#endif /* SO_USE_IFBUFS */
|
||||
OPT_SOCKS5_PASSWORD,
|
||||
OPT_SOCKS5_USERNAME,
|
||||
#if 1 || defined(WITH_SOCKS4)
|
||||
OPT_SOCKSPORT,
|
||||
OPT_SOCKSUSER,
|
||||
|
@ -856,10 +860,10 @@ extern int applyopts_single(struct single *fd, struct opt *opts, enum e_phase ph
|
|||
extern int applyopts_offset(struct single *xfd, struct opt *opts);
|
||||
extern int applyopts_signal(struct single *xfd, struct opt *opts);
|
||||
extern int _xio_openlate(struct single *fd, struct opt *opts);
|
||||
extern int parseopts(const char **a, unsigned int groups, struct opt **opts);
|
||||
extern int parseopts_table(const char **a, unsigned int groups,
|
||||
struct opt **opts,
|
||||
extern int parseopts(const char **a, struct opt **opts);
|
||||
extern int parseopts_table(const char **a, struct opt **opts,
|
||||
const struct optname optionnames[], size_t optionnum);
|
||||
extern int xiocheckopts(struct opt *opts, unsigned int groups);
|
||||
extern struct opt *copyopts(const struct opt *opts, unsigned int groups);
|
||||
extern struct opt *moveopts(struct opt *opts, unsigned int groups);
|
||||
extern int leftopts(const struct opt *opts);
|
||||
|
|
20
xioparam.c
20
xioparam.c
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xioparam.c,v 1.10 2006/06/19 20:30:24 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for xio options handling */
|
||||
|
@ -12,16 +12,28 @@
|
|||
/* options that can be applied to this module */
|
||||
xioopts_t xioopts = {
|
||||
false, /* strictopts */
|
||||
"!!", /* pipesep */
|
||||
"%", /* pipesep */
|
||||
":", /* paramsep */
|
||||
",", /* optionsep */
|
||||
':', /* ip4portsep */
|
||||
':', /* ip6portsep */
|
||||
'\0', /* logopt */
|
||||
NULL, /* syslogfac */
|
||||
'4', /* default_ip */
|
||||
'4' /* preferred_ip */
|
||||
'4', /* preferred_ip */
|
||||
"^", /* reversechar */
|
||||
"|", /* chainsep */
|
||||
8192, /* bufsiz */
|
||||
false, /* verbose */
|
||||
false, /* verbhex */
|
||||
0, /* debug */
|
||||
's', /* logopt */
|
||||
{0,0}, /* total_timeout */
|
||||
{1,0}, /* pollintv */
|
||||
{0,500000}, /* closwait */
|
||||
false, /* lefttoright */
|
||||
false, /* righttoleft */
|
||||
} ;
|
||||
xioopts_t *xioparams = &xioopts;
|
||||
|
||||
|
||||
/* allow application to set xioopen options */
|
||||
|
|
60
xioread.c
60
xioread.c
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "xio-termios.h"
|
||||
#include "xio-socket.h"
|
||||
#include "xio-test.h"
|
||||
#include "xio-readline.h"
|
||||
#include "xio-openssl.h"
|
||||
|
||||
|
@ -21,6 +22,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
int nexthead;
|
||||
#endif
|
||||
struct single *pipe;
|
||||
int fd;
|
||||
int _errno;
|
||||
|
||||
if (file->tag == XIO_TAG_INVALID) {
|
||||
|
@ -50,10 +52,12 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
}
|
||||
}
|
||||
|
||||
fd = XIO_GETRDFD(file);
|
||||
|
||||
switch (pipe->dtype & XIODATA_READMASK) {
|
||||
case XIOREAD_STREAM:
|
||||
do {
|
||||
bytes = Read(pipe->fd, buff, bufsiz);
|
||||
bytes = Read(fd, buff, bufsiz);
|
||||
} while (bytes < 0 && errno == EINTR);
|
||||
if (bytes < 0) {
|
||||
_errno = errno;
|
||||
|
@ -61,12 +65,30 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
#if 1
|
||||
case EPIPE: case ECONNRESET:
|
||||
Warn4("read(%d, %p, "F_Zu"): %s",
|
||||
pipe->fd, buff, bufsiz, strerror(_errno));
|
||||
fd, buff, bufsiz, strerror(_errno));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
Error4("read(%d, %p, "F_Zu"): %s",
|
||||
pipe->fd, buff, bufsiz, strerror(_errno));
|
||||
fd, buff, bufsiz, strerror(_errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case XIODATA_PTY:
|
||||
do {
|
||||
bytes = Read(fd, buff, bufsiz);
|
||||
} while (bytes < 0 && errno == EINTR);
|
||||
if (bytes < 0) {
|
||||
_errno = errno;
|
||||
if (_errno == EIO) {
|
||||
Notice4("read(%d, %p, "F_Zu"): %s (probably PTY closed)",
|
||||
fd, buff, bufsiz, strerror(_errno));
|
||||
return 0;
|
||||
} else {
|
||||
Error4("read(%d, %p, "F_Zu"): %s",
|
||||
fd, buff, bufsiz, strerror(_errno));
|
||||
}
|
||||
errno = _errno;
|
||||
return -1;
|
||||
|
@ -75,17 +97,17 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
|
||||
case XIOREAD_PTY:
|
||||
do {
|
||||
bytes = Read(pipe->fd, buff, bufsiz);
|
||||
bytes = Read(fd, buff, bufsiz);
|
||||
} while (bytes < 0 && errno == EINTR);
|
||||
if (bytes < 0) {
|
||||
_errno = errno;
|
||||
if (_errno == EIO) {
|
||||
Notice4("read(%d, %p, "F_Zu"): %s (probably PTY closed)",
|
||||
pipe->fd, buff, bufsiz, strerror(_errno));
|
||||
fd, buff, bufsiz, strerror(_errno));
|
||||
return 0;
|
||||
} else {
|
||||
Error4("read(%d, %p, "F_Zu"): %s",
|
||||
pipe->fd, buff, bufsiz, strerror(_errno));
|
||||
fd, buff, bufsiz, strerror(_errno));
|
||||
}
|
||||
errno = _errno;
|
||||
return -1;
|
||||
|
@ -100,6 +122,15 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
break;
|
||||
#endif /* WITH_READLINE */
|
||||
|
||||
#if WITH_TEST
|
||||
case XIOREAD_TEST:
|
||||
/* this function prints its error messages */
|
||||
if ((bytes = xioread_test(pipe, buff, bufsiz)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif /* WITH_TEST */
|
||||
|
||||
#if WITH_OPENSSL
|
||||
case XIOREAD_OPENSSL:
|
||||
/* this function prints its error messages */
|
||||
|
@ -118,14 +149,13 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
char infobuff[256];
|
||||
|
||||
do {
|
||||
bytes =
|
||||
Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen);
|
||||
bytes = Recvfrom(fd, buff, bufsiz, 0, &from.soa, &fromlen);
|
||||
} while (bytes < 0 && errno == EINTR);
|
||||
if (bytes < 0) {
|
||||
char infobuff[256];
|
||||
_errno = errno;
|
||||
Error6("recvfrom(%d, %p, "F_Zu", 0, %s, {"F_socklen"}): %s",
|
||||
pipe->fd, buff, bufsiz,
|
||||
fd, buff, bufsiz,
|
||||
sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)),
|
||||
fromlen, strerror(errno));
|
||||
errno = _errno;
|
||||
|
@ -209,7 +239,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
headlen = 4*((struct ip *)buff)->ip_vhl;
|
||||
#endif
|
||||
if (headlen > bytes) {
|
||||
Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd);
|
||||
Warn1("xioread(%d, ...)/IP4: short packet", fd);
|
||||
bytes = 0;
|
||||
} else {
|
||||
memmove(buff, ((char *)buff)+headlen, bytes-headlen);
|
||||
|
@ -286,11 +316,11 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
|
||||
socket_init(pipe->para.socket.la.soa.sa_family, &from);
|
||||
/* get source address */
|
||||
if (xiogetpacketsrc(pipe->fd, &from, &fromlen) < 0) {
|
||||
if (xiogetpacketsrc(fd, &from, &fromlen) < 0) {
|
||||
return STAT_RETRYNOW;
|
||||
}
|
||||
if (xiocheckpeer(pipe, &from, &pipe->para.socket.la) < 0) {
|
||||
Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); /* drop */
|
||||
Recvfrom(fd, buff, bufsiz, 0, &from.soa, &fromlen); /* drop */
|
||||
errno = EAGAIN; return -1;
|
||||
}
|
||||
Info1("permitting packet from %s",
|
||||
|
@ -299,13 +329,13 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
|
||||
do {
|
||||
bytes =
|
||||
Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen);
|
||||
Recvfrom(fd, buff, bufsiz, 0, &from.soa, &fromlen);
|
||||
} while (bytes < 0 && errno == EINTR);
|
||||
if (bytes < 0) {
|
||||
char infobuff[256];
|
||||
_errno = errno;
|
||||
Error6("recvfrom(%d, %p, "F_Zu", 0, %s, "F_socklen"): %s",
|
||||
pipe->fd, buff, bufsiz,
|
||||
fd, buff, bufsiz,
|
||||
sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)),
|
||||
fromlen, strerror(errno));
|
||||
errno = _errno;
|
||||
|
@ -334,7 +364,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
headlen = 4*((struct ip *)buff)->ip_vhl;
|
||||
#endif
|
||||
if (headlen > bytes) {
|
||||
Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd);
|
||||
Warn1("xioread(%d, ...)/IP4: short packet", fd);
|
||||
bytes = 0;
|
||||
} else {
|
||||
memmove(buff, ((char *)buff)+headlen, bytes-headlen);
|
||||
|
|
265
xioshutdown.c
265
xioshutdown.c
|
@ -8,6 +8,9 @@
|
|||
#include "xiosysincludes.h"
|
||||
#include "xioopen.h"
|
||||
|
||||
|
||||
static int xioshut_sleep_kill(pid_t sub, unsigned long usec, int sig);
|
||||
|
||||
static pid_t socat_kill_pid; /* here we pass the pid to be killed in sighandler */
|
||||
|
||||
static void signal_kill_pid(int dummy) {
|
||||
|
@ -15,15 +18,21 @@ static void signal_kill_pid(int dummy) {
|
|||
Kill(socat_kill_pid, SIGTERM);
|
||||
}
|
||||
|
||||
/* how: SHUT_RD, SHUT_WR, or SHUT_RDWR */
|
||||
int xioshutdown(xiofile_t *sock, int how) {
|
||||
int result = 0;
|
||||
|
||||
Debug2("xioshutdown(%p, %d)", sock, how);
|
||||
Debug2("xioshutdown(): dtype=0x%x, howtoshut=0x%04x",
|
||||
sock->stream.dtype, sock->stream.howtoshut);
|
||||
|
||||
if (sock->tag == XIO_TAG_INVALID) {
|
||||
Error("xioshutdown(): invalid file descriptor");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*Debug3("xioshutdown: flags=%d, dtype=%d, howtoclose=%d", sock->stream.flags, sock->stream.dtype, sock->stream.howtoclose);*/
|
||||
if (sock->tag == XIO_TAG_DUAL) {
|
||||
if ((how+1)&1) {
|
||||
result = xioshutdown((xiofile_t *)sock->dual.stream[0], 0);
|
||||
|
@ -31,104 +40,182 @@ int xioshutdown(xiofile_t *sock, int how) {
|
|||
if ((how+1)&2) {
|
||||
result |= xioshutdown((xiofile_t *)sock->dual.stream[1], 1);
|
||||
}
|
||||
|
||||
#if WITH_OPENSSL
|
||||
} else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_OPENSSL) {
|
||||
sycSSL_shutdown (sock->stream.para.openssl.ssl);
|
||||
/*! what about half/full close? */
|
||||
#endif /* WITH_OPENSSL */
|
||||
|
||||
} else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_PIPE) {
|
||||
if ((how+1)&1) {
|
||||
if (Close(sock->stream.fd) < 0) {
|
||||
Info2("close(%d): %s",
|
||||
sock->stream.fd, strerror(errno));
|
||||
}
|
||||
}
|
||||
if ((how+1)&2) {
|
||||
if (Close(sock->stream.para.bipipe.fdout) < 0) {
|
||||
Info2("close(%d): %s",
|
||||
sock->stream.para.bipipe.fdout, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
} else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_2PIPE) {
|
||||
if ((how+1)&1) {
|
||||
if (Close(sock->stream.fd) < 0) {
|
||||
Info2("close(%d): %s",
|
||||
sock->stream.fd, strerror(errno));
|
||||
}
|
||||
}
|
||||
if ((how+1)&2) {
|
||||
if (Close(sock->stream.para.exec.fdout) < 0) {
|
||||
Info2("close(%d): %s",
|
||||
sock->stream.para.exec.fdout, strerror(errno));
|
||||
}
|
||||
}
|
||||
#if WITH_SOCKET
|
||||
} else if (sock->stream.howtoend == END_SHUTDOWN) {
|
||||
if ((result = Shutdown(sock->stream.fd, how)) < 0) {
|
||||
Info3("shutdown(%d, %d): %s",
|
||||
sock->stream.fd, how, strerror(errno));
|
||||
}
|
||||
} else if (sock->stream.howtoend == END_SHUTDOWN_KILL) {
|
||||
if ((result = Shutdown(sock->stream.fd, how)) < 0) {
|
||||
Info3("shutdown(%d, %d): %s",
|
||||
sock->stream.fd, how, strerror(errno));
|
||||
}
|
||||
if ((sock->stream.flags&XIO_ACCMODE) == XIO_WRONLY) {
|
||||
/* the child process might want to flush some data before terminating
|
||||
*/
|
||||
int status = 0;
|
||||
|
||||
/* we wait for the child process to die, but to prevent timeout
|
||||
we raise an alarm after some time.
|
||||
NOTE: the alarm does not terminate waitpid() on Linux/glibc (BUG?),
|
||||
therefore we have to do the kill in the signal handler */
|
||||
Signal(SIGALRM, signal_kill_pid);
|
||||
socat_kill_pid = sock->stream.para.exec.pid;
|
||||
#if HAVE_SETITIMER
|
||||
/*! with next feature release, we get usec resolution and an option */
|
||||
#else
|
||||
Alarm(1 /*! sock->stream.para.exec.waitdie */);
|
||||
#endif /* !HAVE_SETITIMER */
|
||||
if (Waitpid(sock->stream.para.exec.pid, &status, 0) < 0) {
|
||||
Warn3("waitpid("F_pid", %p, 0): %s",
|
||||
sock->stream.para.exec.pid, &status, strerror(errno));
|
||||
}
|
||||
Alarm(0);
|
||||
}
|
||||
} else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_RECVFROM) {
|
||||
if (how >= 1) {
|
||||
if (Close(sock->stream.fd) < 0) {
|
||||
Info2("close(%d): %s",
|
||||
sock->stream.fd, strerror(errno));
|
||||
}
|
||||
sock->stream.eof = 2;
|
||||
sock->stream.fd = -1;
|
||||
}
|
||||
#endif /* WITH_SOCKET */
|
||||
#if 0
|
||||
} else {
|
||||
Error1("xioshutdown(): bad data type specification %d", sock->stream.dtype);
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
}
|
||||
#if 0
|
||||
else if (sock->stream.howtoend == END_CLOSE &&
|
||||
sock->stream.dtype == DATA_STREAM) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* let us bring how nearer to the resulting action */
|
||||
if ((sock->stream.flags&XIO_ACCMODE) == XIO_WRONLY) {
|
||||
how = ((how+1) & ~(SHUT_RD+1)) - 1;
|
||||
} else if ((sock->stream.flags&XIO_ACCMODE) == XIO_RDONLY) {
|
||||
how = ((how+1) & ~(SHUT_WR+1)) - 1;
|
||||
}
|
||||
|
||||
/* here handle special shutdown functions */
|
||||
switch (sock->stream.howtoshut) {
|
||||
#if WITH_OPENSSL
|
||||
case XIOSHUT_OPENSSL:
|
||||
sycSSL_shutdown(sock->stream.para.openssl.ssl);
|
||||
/*! what about half/full close? */
|
||||
return 0;
|
||||
#endif /* WITH_OPENSSL */
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (how == SHUT_RDWR) {
|
||||
/* in this branch we handle only shutdown actions where read and write
|
||||
shutdown are not independent */
|
||||
|
||||
switch (sock->stream.howtoshut) {
|
||||
#if 0
|
||||
case XIODATA_STREAM:
|
||||
switch (sock->stream.howtoclose) {
|
||||
#if WITH_SOCKET
|
||||
case END_SHUTDOWN:
|
||||
if ((result = Shutdown(sock->stream.fd1, how)) < 0) {
|
||||
Info3("shutdown(%d, %d): %s",
|
||||
sock->stream.fd1, how, strerror(errno));
|
||||
}
|
||||
break;
|
||||
case END_SHUTDOWN_KILL:
|
||||
if ((result = Shutdown(sock->stream.fd1, how)) < 0) {
|
||||
Info3("shutdown(%d, %d): %s",
|
||||
sock->stream.fd1, how, strerror(errno));
|
||||
}
|
||||
break;
|
||||
#endif /* WITH_SOCKET */
|
||||
case END_CLOSE:
|
||||
Close(sock->stream.fd1);
|
||||
#if WITH_TERMIOS
|
||||
if (sock->stream.ttyvalid) {
|
||||
if (Tcsetattr(sock->stream.fd, 0, &sock->stream.savetty) < 0) {
|
||||
if (Tcsetattr(sock->stream.fd1, 0, &sock->stream.savetty) < 0) {
|
||||
Warn2("cannot restore terminal settings on fd %d: %s",
|
||||
sock->stream.fd, strerror(errno));
|
||||
sock->stream.fd1, strerror(errno));
|
||||
}
|
||||
}
|
||||
#endif /* WITH_TERMIOS */
|
||||
/*PASSTHROUGH*/
|
||||
case END_NONE:
|
||||
break;
|
||||
default:
|
||||
Error1("xioshutdown(): bad end action 0x%x", sock->stream.howtoclose);
|
||||
return -1;
|
||||
}
|
||||
#if WITH_SOCKET
|
||||
case XIODATA_RECVFROM:
|
||||
if (how >= 1) {
|
||||
if (Close(sock->stream.fd1) < 0) {
|
||||
Info2("close(%d): %s",
|
||||
sock->stream.fd1, strerror(errno));
|
||||
}
|
||||
sock->stream.eof = 2;
|
||||
sock->stream.fd1 = -1;
|
||||
}
|
||||
break;
|
||||
#endif /* WITH_SOCKET */
|
||||
#endif /* 0 */
|
||||
default:
|
||||
Error1("xioshutdown(): bad data type specification 0x%x", sock->stream.dtype);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((how+1) & 1) { /* contains SHUT_RD */
|
||||
switch (sock->stream.dtype & XIODATA_READMASK) {
|
||||
/* shutdown read channel */
|
||||
|
||||
case XIOREAD_STREAM:
|
||||
case XIODATA_2PIPE:
|
||||
if (Close(sock->stream.fd1) < 0) {
|
||||
Info2("close(%d): %s",
|
||||
sock->stream.fd1, strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((how+1) & 2) { /* contains SHUT_WR */
|
||||
/* shutdown write channel */
|
||||
int fd;
|
||||
|
||||
if (sock->stream.fdtype == FDTYPE_DOUBLE) {
|
||||
fd = sock->stream.fd2;
|
||||
} else {
|
||||
fd = sock->stream.fd1;
|
||||
}
|
||||
|
||||
switch (sock->stream.howtoshut & XIOSHUTWR_MASK) {
|
||||
|
||||
case XIOSHUTWR_CLOSE:
|
||||
if (Close(fd) < 0) {
|
||||
Info2("close(%d): %s", fd, strerror(errno));
|
||||
}
|
||||
/*PASSTHROUGH*/
|
||||
case XIOSHUTWR_NONE:
|
||||
break;
|
||||
|
||||
#if WITH_SOCKET
|
||||
case XIOSHUTWR_DOWN:
|
||||
if (Shutdown(fd, SHUT_WR) < 0) {
|
||||
Info2("shutdown(%d, SHUT_WR): %s", fd, strerror(errno));
|
||||
}
|
||||
break;
|
||||
#endif /* WITH_SOCKET */
|
||||
|
||||
#if 0
|
||||
case XIOSHUTWR_DOWN_KILL:
|
||||
if (Shutdown(fd, SHUT_WR) < 0) {
|
||||
Info2("shutdown(%d, SHUT_WR): %s", fd, strerror(errno));
|
||||
}
|
||||
#endif
|
||||
case XIOSHUTWR_SIGHUP:
|
||||
/* the child process might want to flush some data before
|
||||
terminating */
|
||||
xioshut_sleep_kill(sock->stream.child.pid, 0, SIGHUP);
|
||||
break;
|
||||
case XIOSHUTWR_SIGTERM:
|
||||
/* the child process might want to flush some data before
|
||||
terminating */
|
||||
xioshut_sleep_kill(sock->stream.child.pid, 1000000, SIGTERM);
|
||||
break;
|
||||
case XIOSHUTWR_SIGKILL:
|
||||
/* the child process might want to flush some data before
|
||||
terminating */
|
||||
xioshut_sleep_kill(sock->stream.child.pid, 1000000, SIGKILL);
|
||||
break;
|
||||
|
||||
default:
|
||||
Error1("xioshutdown(): unhandled howtoshut=0x%x during SHUT_WR",
|
||||
sock->stream.howtoshut);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* wait some time and then send signal to sub process. This is useful after
|
||||
shutting down the connection to give process some time to flush its output
|
||||
data */
|
||||
static int xioshut_sleep_kill(pid_t sub, unsigned long usec, int sig) {
|
||||
struct sigaction act;
|
||||
int status = 0;
|
||||
|
||||
/* we wait for the child process to die, but to prevent timeout
|
||||
we raise an alarm after some time. */
|
||||
/* NOTE: the alarm does not terminate waitpid() on Linux/glibc
|
||||
(BUG?),
|
||||
therefore we have to do the kill in the signal handler */
|
||||
Signal(SIGALRM, signal_kill_pid);
|
||||
socat_kill_pid = sub;
|
||||
#if HAVE_SETITIMER
|
||||
/*! with next feature release, we get usec resolution and an option
|
||||
*/
|
||||
#else
|
||||
Alarm(1 /*! sock->stream.child.waitdie */);
|
||||
#endif /* !HAVE_SETITIMER */
|
||||
if (Waitpid(sub, &status, 0) < 0) {
|
||||
Warn3("waitpid("F_pid", %p, 0): %s",
|
||||
sub, &status, strerror(errno));
|
||||
}
|
||||
Alarm(0);
|
||||
return 0;
|
||||
}
|
||||
|
|
167
xiosigchld.c
167
xiosigchld.c
|
@ -1,5 +1,5 @@
|
|||
/* $Id: xiosigchld.c,v 1.21 2006/12/28 14:38:38 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this is the source of the extended child signal handler */
|
||||
|
@ -7,23 +7,42 @@
|
|||
|
||||
#include "xiosysincludes.h"
|
||||
#include "xioopen.h"
|
||||
#include "xiosigchld.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* we maintain a table of all known child processes */
|
||||
/* for now, we use a very primitive data structure - just an unsorted, size
|
||||
limited array */
|
||||
|
||||
/*!! with socat, at most 4 exec children exist */
|
||||
#define XIO_MAXCHILDPIDS 16
|
||||
|
||||
struct _xiosigchld_child {
|
||||
pid_t pid;
|
||||
void (*sigaction)(int, siginfo_t *, void *);
|
||||
void *context;
|
||||
} ;
|
||||
|
||||
static struct _xiosigchld_child * _xiosigchld_find(pid_t pid);
|
||||
|
||||
static struct _xiosigchld_child xio_childpids[XIO_MAXCHILDPIDS];
|
||||
|
||||
#if 1 /*!!!*/
|
||||
/*!! with socat, at most 4 managed children exist */
|
||||
pid_t diedunknown1; /* child died before it is registered */
|
||||
pid_t diedunknown2;
|
||||
pid_t diedunknown3;
|
||||
pid_t diedunknown4;
|
||||
#endif
|
||||
|
||||
|
||||
/* register for a xio filedescriptor a callback (handler).
|
||||
when a SIGCHLD occurs, the signal handler will ??? */
|
||||
int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)) {
|
||||
if (xfd->tag != XIO_TAG_DUAL) {
|
||||
xfd->stream.sigchild = callback;
|
||||
xfd->stream.child.sigchild = callback;
|
||||
} else {
|
||||
xfd->dual.stream[0]->sigchild = callback;
|
||||
xfd->dual.stream[1]->sigchild = callback;
|
||||
xfd->dual.stream[0]->child.sigchild = callback;
|
||||
xfd->dual.stream[1]->child.sigchild = callback;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -31,9 +50,9 @@ int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)) {
|
|||
/* exec'd child has died, perform appropriate changes to descriptor */
|
||||
static int sigchld_stream(struct single *file) {
|
||||
/*!! call back to application */
|
||||
file->para.exec.pid = 0;
|
||||
if (file->sigchild) {
|
||||
return (*file->sigchild)(file);
|
||||
file->child.pid = 0;
|
||||
if (file->child.sigchild) {
|
||||
return (*file->child.sigchild)(file);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -43,12 +62,9 @@ static int xio_checkchild(xiofile_t *socket, int socknum, pid_t deadchild) {
|
|||
int retval;
|
||||
if (socket != NULL) {
|
||||
if (socket->tag != XIO_TAG_DUAL) {
|
||||
if ((socket->stream.howtoend == END_KILL ||
|
||||
socket->stream.howtoend == END_CLOSE_KILL ||
|
||||
socket->stream.howtoend == END_SHUTDOWN_KILL) &&
|
||||
socket->stream.para.exec.pid == deadchild) {
|
||||
if (socket->stream.child.pid == deadchild) {
|
||||
Info2("exec'd process %d on socket %d terminated",
|
||||
socket->stream.para.exec.pid, socknum);
|
||||
socket->stream.child.pid, socknum);
|
||||
sigchld_stream(&socket->stream);
|
||||
return 1;
|
||||
}
|
||||
|
@ -64,17 +80,22 @@ static int xio_checkchild(xiofile_t *socket, int socknum, pid_t deadchild) {
|
|||
|
||||
/* this is the "physical" signal handler for SIGCHLD */
|
||||
/* the current socat/xio implementation knows two kinds of children:
|
||||
exec/system addresses perform a fork: these children are registered and
|
||||
there death influences the parents flow;
|
||||
exec/system addresses perform a fork: their children are registered and
|
||||
their death's influence the parents' flow;
|
||||
listen-socket with fork children: these children are "anonymous" and their
|
||||
death does not affect the parent process (now; maybe we have a child
|
||||
process counter later) */
|
||||
void childdied(int signum) {
|
||||
void childdied(int signum
|
||||
#if HAVE_SIGACTION
|
||||
, siginfo_t *siginfo, void *context
|
||||
#endif /* HAVE_SIGACTION */
|
||||
) {
|
||||
pid_t pid;
|
||||
int _errno;
|
||||
int status = 0;
|
||||
bool wassig = false;
|
||||
int i;
|
||||
struct _xiosigchld_child *entry;
|
||||
|
||||
_errno = errno; /* save current value; e.g., select() on Cygwin seems
|
||||
to set it to EINTR _before_ handling the signal, and
|
||||
|
@ -105,6 +126,7 @@ void childdied(int signum) {
|
|||
errno = _errno;
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
/*! indent */
|
||||
/* check if it was a registered child process */
|
||||
i = 0;
|
||||
|
@ -128,6 +150,15 @@ void childdied(int signum) {
|
|||
Debug("saving pid in diedunknown4");
|
||||
}
|
||||
}
|
||||
#else
|
||||
entry = _xiosigchld_find(pid);
|
||||
if (entry == NULL) {
|
||||
Info("dead child "F_pid" died unknown");
|
||||
} else {
|
||||
(*entry->sigaction)(signum, siginfo, entry->context);
|
||||
xiosigchld_unregister(pid);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) == 0) {
|
||||
|
@ -157,3 +188,107 @@ void childdied(int signum) {
|
|||
Info("childdied() finished");
|
||||
errno = _errno;
|
||||
}
|
||||
|
||||
|
||||
/* search for given pid in child process table. returns matching entry on
|
||||
success, or NULL if not found. Can be used with pid==0 to look for an empty
|
||||
entry. */
|
||||
static struct _xiosigchld_child *
|
||||
_xiosigchld_find(pid_t pid) {
|
||||
|
||||
int i;
|
||||
|
||||
/* is it already registered? */
|
||||
for (i = 0; i < XIO_MAXCHILDPIDS; ++i) {
|
||||
if (pid == xio_childpids[i].pid) {
|
||||
return &xio_childpids[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* add a child process to the table
|
||||
returns 0 on success (registered or reregistered child)
|
||||
returns -1 on table overflow
|
||||
*/
|
||||
int xiosigchld_register(pid_t pid,
|
||||
void (*sigaction)(int, siginfo_t *, void *),
|
||||
void *context) {
|
||||
struct _xiosigchld_child *entry;
|
||||
|
||||
/* is it already registered? */
|
||||
if (entry = _xiosigchld_find(pid)) {
|
||||
/* was already registered, override */
|
||||
entry->sigaction = sigaction;
|
||||
entry->context = context;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* try to register it */
|
||||
if (entry = _xiosigchld_find(0)) {
|
||||
entry->pid = pid;
|
||||
entry->sigaction = sigaction;
|
||||
entry->context = context;
|
||||
return 0;
|
||||
}
|
||||
Warn("xiosigchld_register(): table overflow");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* remove a child process to the table
|
||||
returns 0 on success
|
||||
returns 1 if pid was not found in table
|
||||
*/
|
||||
int xiosigchld_unregister(pid_t pid) {
|
||||
struct _xiosigchld_child *entry;
|
||||
|
||||
/* is it already registered? */
|
||||
if (entry = _xiosigchld_find(pid)) {
|
||||
/* found, remove it from table */
|
||||
entry->pid = 0;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* clear the child process table */
|
||||
/* especially interesting after fork() in child process
|
||||
returns 0
|
||||
*/
|
||||
int xiosigchld_clearall(void) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < XIO_MAXCHILDPIDS; ++i) {
|
||||
xio_childpids[i].pid = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void xiosigaction_subaddr_ok(int signum, siginfo_t *siginfo, void *ucontext) {
|
||||
pid_t subpid = siginfo->si_pid;
|
||||
struct _xiosigchld_child *entry;
|
||||
xiosingle_t *xfd;
|
||||
|
||||
entry = _xiosigchld_find(subpid);
|
||||
if (entry == NULL) {
|
||||
Warn1("SIGUSR1 from unregistered process "F_pid, subpid);
|
||||
return;
|
||||
}
|
||||
xfd = entry->context;
|
||||
xfd->subaddrstat = 1;
|
||||
}
|
||||
|
||||
void xiosigaction_child(int signum, siginfo_t *siginfo, void *ucontext) {
|
||||
pid_t subpid = siginfo->si_pid;
|
||||
xiosingle_t *xfd = ucontext;
|
||||
|
||||
/* the sub process that is connected to this xio address has terminated */
|
||||
Notice2("sub process "F_pid" died, setting in xfd %p", subpid, xfd);
|
||||
xfd->subaddrstat = -1;
|
||||
xfd->subaddrexit = siginfo->si_status;
|
||||
if (xfd->child.sigchild) {
|
||||
(*xfd->child.sigchild)(xfd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
30
xiosigchld.h
Normal file
30
xiosigchld.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* $Id$ */
|
||||
/* Copyright Gerhard Rieger 2006 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xiosigchld_h
|
||||
#define __xiosigchld_h 1
|
||||
|
||||
extern pid_t diedunknown1; /* child died before it is registered */
|
||||
extern pid_t diedunknown2;
|
||||
extern pid_t diedunknown3;
|
||||
extern pid_t diedunknown4;
|
||||
|
||||
extern int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *));
|
||||
extern void childdied(int signum
|
||||
#if HAVE_SIGACTION
|
||||
, siginfo_t *siginfo, void *context
|
||||
#endif /* HAVE_SIGACTION */
|
||||
);
|
||||
|
||||
extern int
|
||||
xiosigchld_register(pid_t pid,
|
||||
void (*sigaction)(int, siginfo_t *, void *),
|
||||
void *context);
|
||||
extern int xiosigchld_unregister(pid_t pid);
|
||||
extern int xiosigchld_clearall(void);
|
||||
|
||||
extern void xiosigaction_subaddr_ok(int signum, siginfo_t *siginfo, void *ucontext);
|
||||
extern void xiosigaction_child(int signum, siginfo_t *siginfo, void *ucontext);
|
||||
|
||||
#endif /* !defined(__xiosigchld_h) */
|
186
xiosocketpair.c
Normal file
186
xiosocketpair.c
Normal file
|
@ -0,0 +1,186 @@
|
|||
/* $Id$ */
|
||||
/* Copyright Gerhard Rieger 2007 */
|
||||
/* 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 "error.h"
|
||||
#include "xio.h"
|
||||
|
||||
#if defined(HAVE_DEV_PTMX)
|
||||
# define PTMX "/dev/ptmx" /* Linux */
|
||||
#elif HAVE_DEV_PTC
|
||||
# define PTMX "/dev/ptc" /* AIX */
|
||||
#endif
|
||||
|
||||
#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 xiosocketpair(xiofile_t **xfd1p, xiofile_t **xfd2p, int how, ...) {
|
||||
va_list ap;
|
||||
xiofile_t *xfd1, *xfd2;
|
||||
int result = 0;
|
||||
|
||||
if ((xfd1 = xioallocfd()) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if ((xfd2 = xioallocfd()) == NULL) {
|
||||
xiofreefd(xfd1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (how) {
|
||||
case 0: /* socketpair */
|
||||
{
|
||||
int sv[2];
|
||||
int domain, type, protocol;
|
||||
|
||||
va_start(ap, how);
|
||||
domain = va_arg(ap, int);
|
||||
type = va_arg(ap, int);
|
||||
protocol = va_arg(ap, int);
|
||||
va_end(ap);
|
||||
if (Socketpair(domain, type, protocol, sv) < 0) {
|
||||
Error5("socketpair(%d, %d, %d, %p): %s",
|
||||
domain, type, protocol, sv, strerror(errno));
|
||||
xiofreefd(xfd1); xiofreefd(xfd2);
|
||||
return -1;
|
||||
}
|
||||
assert(xfd1->stream.fdtype == FDTYPE_SINGLE);
|
||||
xfd1->stream.fd1 = sv[0];
|
||||
assert(xfd2->stream.fdtype == FDTYPE_SINGLE);
|
||||
xfd2->stream.fd1 = sv[1];
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
int filedes1[2], filedes2[2];
|
||||
if (Pipe(filedes1) < 0) {
|
||||
Error2("pipe(%p): %s", filedes1, strerror(errno));
|
||||
xiofreefd(xfd1); xiofreefd(xfd2);
|
||||
return -1;
|
||||
}
|
||||
if (Pipe(filedes2) < 0) {
|
||||
Error2("pipe(%p): %s", filedes2, strerror(errno));
|
||||
xiofreefd(xfd1); xiofreefd(xfd2);
|
||||
Close(filedes1[0]); Close(filedes1[1]);
|
||||
return -1;
|
||||
}
|
||||
xfd1->stream.fd1 = filedes1[0];
|
||||
xfd1->stream.fd2 = filedes2[1];
|
||||
xfd1->stream.fdtype = FDTYPE_DOUBLE;
|
||||
xfd1->stream.dtype = XIODATA_2PIPE;
|
||||
xfd2->stream.fd1 = filedes2[0];
|
||||
xfd2->stream.fd2 = filedes1[1];
|
||||
xfd2->stream.fdtype = FDTYPE_DOUBLE;
|
||||
xfd2->stream.dtype = XIODATA_2PIPE;
|
||||
}
|
||||
break;
|
||||
|
||||
#if HAVE_DEV_PTMX || HAVE_DEV_PTC
|
||||
case 2: /* pty (master, slave) */
|
||||
{
|
||||
int useptmx;
|
||||
char ptyname[MAXPTYNAMELEN];
|
||||
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);*/
|
||||
#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));
|
||||
} 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);
|
||||
#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);*/
|
||||
}
|
||||
|
||||
#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 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 */
|
||||
|
||||
default:
|
||||
Error1("undefined socketpair mechanism %d", how);
|
||||
xiofreefd(xfd1); xiofreefd(xfd2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*xfd1p = xfd1;
|
||||
*xfd2p = xfd2;
|
||||
return 0;
|
||||
}
|
||||
|
11
xiostatic.h
Normal file
11
xiostatic.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
/* $Id$ */
|
||||
/* Copyright Gerhard Rieger 2006 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* libxio internal global variables */
|
||||
#ifndef __xiostatic_h
|
||||
#define __xiostatic_h 1
|
||||
|
||||
extern int xio_flags;
|
||||
|
||||
#endif /* !defined(__xiostatic_h) */
|
302
xiotransfer.c
Normal file
302
xiotransfer.c
Normal file
|
@ -0,0 +1,302 @@
|
|||
/* $Id$ */
|
||||
/* Copyright Gerhard Rieger 2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this is the source file of the data transfer function */
|
||||
|
||||
#include "xiosysincludes.h"
|
||||
|
||||
#include "mytypes.h"
|
||||
#include "compat.h"
|
||||
#include "error.h"
|
||||
|
||||
#include "sycls.h"
|
||||
#include "xio.h"
|
||||
|
||||
static
|
||||
int cv_newline(unsigned char **buff, ssize_t *bytes, int lineterm1, int lineterm2);
|
||||
|
||||
|
||||
#define MAXTIMESTAMPLEN 128
|
||||
/* prints the timestamp to the buffer and terminates it with '\0'. This buffer
|
||||
should be at least MAXTIMESTAMPLEN bytes long.
|
||||
returns 0 on success or -1 if an error occurred */
|
||||
int gettimestamp(char *timestamp) {
|
||||
size_t bytes;
|
||||
#if HAVE_GETTIMEOFDAY || 1
|
||||
struct timeval now;
|
||||
int result;
|
||||
time_t nowt;
|
||||
#else /* !HAVE_GETTIMEOFDAY */
|
||||
time_t now;
|
||||
#endif /* !HAVE_GETTIMEOFDAY */
|
||||
|
||||
#if HAVE_GETTIMEOFDAY || 1
|
||||
result = gettimeofday(&now, NULL);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
} else {
|
||||
nowt = now.tv_sec;
|
||||
#if HAVE_STRFTIME
|
||||
bytes = strftime(timestamp, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt));
|
||||
bytes += sprintf(timestamp+19, "."F_tv_usec" ", now.tv_usec);
|
||||
#else
|
||||
strcpy(timestamp, ctime(&nowt));
|
||||
bytes = strlen(timestamp);
|
||||
#endif
|
||||
}
|
||||
#else /* !HAVE_GETTIMEOFDAY */
|
||||
now = time(NULL); if (now == (time_t)-1) {
|
||||
return -1;
|
||||
} else {
|
||||
#if HAVE_STRFTIME
|
||||
bytes = strftime(timestamp, 21, "%Y/%m/%d %H:%M:%S ", localtime(&now));
|
||||
#else
|
||||
strcpy(timestamp, ctime(&now));
|
||||
bytes = strlen(timestamp);
|
||||
#endif
|
||||
}
|
||||
#endif /* !HAVE_GETTIMEOFDAY */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const char *prefixltor = "> ";
|
||||
static const char *prefixrtol = "< ";
|
||||
static unsigned long numltor;
|
||||
static unsigned long numrtol;
|
||||
/* print block header (during verbose or hex dump)
|
||||
returns 0 on success or -1 if an error occurred */
|
||||
static int
|
||||
xioprintblockheader(FILE *file, size_t bytes, bool righttoleft) {
|
||||
char timestamp[MAXTIMESTAMPLEN];
|
||||
char buff[128+MAXTIMESTAMPLEN];
|
||||
if (gettimestamp(timestamp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (righttoleft) {
|
||||
sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
|
||||
prefixrtol, timestamp, bytes, numrtol, numrtol+bytes-1);
|
||||
numrtol+=bytes;
|
||||
} else {
|
||||
sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
|
||||
prefixltor, timestamp, bytes, numltor, numltor+bytes-1);
|
||||
numltor+=bytes;
|
||||
}
|
||||
fputs(buff, file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* inpipe is suspected to have read data available; read at most bufsiz bytes
|
||||
and transfer them to outpipe. Perform required data conversions.
|
||||
buff should be at least twice as large as bufsiz, to allow all standard
|
||||
conversions. Returns the number of bytes written, or 0 on EOF or <0 if an
|
||||
error occurred or when data was read but none written due to conversions
|
||||
(with EAGAIN). EAGAIN also occurs when reading from a nonblocking FD where
|
||||
the file has a mandatory lock.
|
||||
If 0 bytes were read (EOF), it does NOT shutdown or close a channel, and it
|
||||
does NOT write a zero bytes block.
|
||||
*/
|
||||
/* inpipe, outpipe must be single descriptors (not dual!) */
|
||||
int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
||||
unsigned char **buff, size_t bufsiz, bool righttoleft) {
|
||||
ssize_t bytes, writt;
|
||||
|
||||
bytes = xioread(inpipe, *buff, bufsiz);
|
||||
if (bytes < 0) {
|
||||
if (errno != EAGAIN)
|
||||
XIO_RDSTREAM(inpipe)->eof = 2;
|
||||
/*xioshutdown(inpipe, SHUT_RD);*/
|
||||
return -1;
|
||||
}
|
||||
if (bytes == 0) {
|
||||
writt = 0;
|
||||
}
|
||||
|
||||
else /* if (bytes > 0)*/ {
|
||||
|
||||
if (XIO_RDSTREAM(inpipe)->lineterm !=
|
||||
XIO_WRSTREAM(outpipe)->lineterm) {
|
||||
cv_newline(buff, &bytes,
|
||||
XIO_RDSTREAM(inpipe)->lineterm,
|
||||
XIO_WRSTREAM(outpipe)->lineterm);
|
||||
}
|
||||
if (bytes == 0) {
|
||||
errno = EAGAIN; return -1;
|
||||
}
|
||||
|
||||
if (xioparams->verbose && xioparams->verbhex) {
|
||||
/* Hack-o-rama */
|
||||
size_t i = 0;
|
||||
size_t j;
|
||||
size_t N = 16;
|
||||
const unsigned char *end, *s, *t;
|
||||
s = *buff;
|
||||
end = (*buff)+bytes;
|
||||
xioprintblockheader(stderr, bytes, righttoleft);
|
||||
while (s < end) {
|
||||
/*! prefix? */
|
||||
j = Min(N, (size_t)(end-s));
|
||||
|
||||
/* print hex */
|
||||
t = s;
|
||||
i = 0;
|
||||
while (i < j) {
|
||||
int c = *t++;
|
||||
fprintf(stderr, " %02x", c);
|
||||
++i;
|
||||
if (c == '\n') break;
|
||||
}
|
||||
|
||||
/* fill hex column */
|
||||
while (i < N) {
|
||||
fputs(" ", stderr);
|
||||
++i;
|
||||
}
|
||||
fputs(" ", stderr);
|
||||
|
||||
/* print acsii */
|
||||
t = s;
|
||||
i = 0;
|
||||
while (i < j) {
|
||||
int c = *t++;
|
||||
if (c == '\n') {
|
||||
fputc('.', stderr);
|
||||
break;
|
||||
}
|
||||
if (!isprint(c))
|
||||
c = '.';
|
||||
fputc(c, stderr);
|
||||
++i;
|
||||
}
|
||||
|
||||
fputc('\n', stderr);
|
||||
s = t;
|
||||
}
|
||||
fputs("--\n", stderr);
|
||||
} else if (xioparams->verbose) {
|
||||
size_t i = 0;
|
||||
xioprintblockheader(stderr, bytes, righttoleft);
|
||||
while (i < (size_t)bytes) {
|
||||
int c = (*buff)[i];
|
||||
if (i > 0 && (*buff)[i-1] == '\n')
|
||||
/*! prefix? */;
|
||||
switch (c) {
|
||||
case '\a' : fputs("\\a", stderr); break;
|
||||
case '\b' : fputs("\\b", stderr); break;
|
||||
case '\t' : fputs("\t", stderr); break;
|
||||
case '\n' : fputs("\n", stderr); break;
|
||||
case '\v' : fputs("\\v", stderr); break;
|
||||
case '\f' : fputs("\\f", stderr); break;
|
||||
case '\r' : fputs("\\r", stderr); break;
|
||||
case '\\' : fputs("\\\\", stderr); break;
|
||||
default:
|
||||
if (!isprint(c))
|
||||
c = '.';
|
||||
fputc(c, stderr);
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
} else if (xioparams->verbhex) {
|
||||
int i;
|
||||
/*! prefix? */
|
||||
for (i = 0; i < bytes; ++i) {
|
||||
fprintf(stderr, " %02x", (*buff)[i]);
|
||||
}
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
writt = xiowrite(outpipe, *buff, bytes);
|
||||
if (writt < 0) {
|
||||
/* EAGAIN when nonblocking but a mandatory lock is on file.
|
||||
the problem with EAGAIN is that the read cannot be repeated,
|
||||
so we need to buffer the data and try to write it later
|
||||
again. not yet implemented, sorry. */
|
||||
#if 0
|
||||
if (errno == EPIPE) {
|
||||
return 0; /* can no longer write; handle like EOF */
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
} else {
|
||||
Info3("transferred "F_Zu" bytes from %d to %d",
|
||||
writt, XIO_GETRDFD(inpipe), XIO_GETWRFD(outpipe));
|
||||
}
|
||||
}
|
||||
return writt;
|
||||
}
|
||||
|
||||
#define CR '\r'
|
||||
#define LF '\n'
|
||||
|
||||
|
||||
static int cv_newline(unsigned char **buff, ssize_t *bytes,
|
||||
int lineterm1, int lineterm2) {
|
||||
/* must perform newline changes */
|
||||
if (lineterm1 <= LINETERM_CR && lineterm2 <= LINETERM_CR) {
|
||||
/* no change in data length */
|
||||
unsigned char from, to, *p, *z;
|
||||
if (lineterm1 == LINETERM_RAW) {
|
||||
from = '\n'; to = '\r';
|
||||
} else {
|
||||
from = '\r'; to = '\n';
|
||||
}
|
||||
z = *buff + *bytes;
|
||||
p = *buff;
|
||||
while (p < z) {
|
||||
if (*p == from) *p = to;
|
||||
++p;
|
||||
}
|
||||
|
||||
} else if (lineterm1 == LINETERM_CRNL) {
|
||||
/* buffer becomes shorter */
|
||||
unsigned char to, *s, *t, *z;
|
||||
if (lineterm2 == LINETERM_RAW) {
|
||||
to = '\n';
|
||||
} else {
|
||||
to = '\r';
|
||||
}
|
||||
z = *buff + *bytes;
|
||||
s = t = *buff;
|
||||
while (s < z) {
|
||||
if (*s == '\r') {
|
||||
++s;
|
||||
continue;
|
||||
}
|
||||
if (*s == '\n') {
|
||||
*t++ = to; ++s;
|
||||
} else {
|
||||
*t++ = *s++;
|
||||
}
|
||||
}
|
||||
*bytes = t - *buff;
|
||||
} else {
|
||||
/* buffer becomes longer, must alloc another space */
|
||||
unsigned char *buf2;
|
||||
unsigned char from; unsigned char *s, *t, *z;
|
||||
if (lineterm1 == LINETERM_RAW) {
|
||||
from = '\n';
|
||||
} else {
|
||||
from = '\r';
|
||||
}
|
||||
if ((buf2 = Malloc(2*xioparams->bufsiz + 1)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
s = *buff; t = buf2; z = *buff + *bytes;
|
||||
while (s < z) {
|
||||
if (*s == from) {
|
||||
*t++ = '\r'; *t++ = '\n';
|
||||
++s;
|
||||
continue;
|
||||
} else {
|
||||
*t++ = *s++;
|
||||
}
|
||||
}
|
||||
free(*buff);
|
||||
*buff = buf2;
|
||||
*bytes = t - buf2;;
|
||||
}
|
||||
return 0;
|
||||
}
|
47
xiowrite.c
47
xiowrite.c
|
@ -8,6 +8,7 @@
|
|||
#include "xiosysincludes.h"
|
||||
#include "xioopen.h"
|
||||
|
||||
#include "xio-test.h"
|
||||
#include "xio-readline.h"
|
||||
#include "xio-openssl.h"
|
||||
|
||||
|
@ -20,6 +21,7 @@
|
|||
ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
|
||||
ssize_t writt;
|
||||
struct single *pipe;
|
||||
int fd;
|
||||
int _errno;
|
||||
|
||||
if (file->tag == XIO_TAG_INVALID) {
|
||||
|
@ -46,11 +48,13 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
|
|||
}
|
||||
#endif /* WITH_READLINE */
|
||||
|
||||
fd = XIO_GETWRFD(file);
|
||||
|
||||
switch (pipe->dtype & XIODATA_WRITEMASK) {
|
||||
|
||||
case XIOWRITE_STREAM:
|
||||
do {
|
||||
writt = Write(pipe->fd, buff, bytes);
|
||||
writt = Write(fd, buff, bytes);
|
||||
} while (writt < 0 && errno == EINTR);
|
||||
if (writt < 0) {
|
||||
_errno = errno;
|
||||
|
@ -59,13 +63,13 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
|
|||
case ECONNRESET:
|
||||
if (pipe->cool_write) {
|
||||
Notice4("write(%d, %p, "F_Zu"): %s",
|
||||
pipe->fd, buff, bytes, strerror(_errno));
|
||||
fd, buff, bytes, strerror(_errno));
|
||||
break;
|
||||
}
|
||||
/*PASSTRHOUGH*/
|
||||
default:
|
||||
Error4("write(%d, %p, "F_Zu"): %s",
|
||||
pipe->fd, buff, bytes, strerror(_errno));
|
||||
fd, buff, bytes, strerror(_errno));
|
||||
}
|
||||
errno = _errno;
|
||||
return -1;
|
||||
|
@ -85,14 +89,14 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
|
|||
/*socklen_t fromlen;*/
|
||||
|
||||
do {
|
||||
writt = Sendto(pipe->fd, buff, bytes, 0,
|
||||
writt = Sendto(fd, buff, bytes, 0,
|
||||
&pipe->peersa.soa, pipe->salen);
|
||||
} while (writt < 0 && errno == EINTR);
|
||||
if (writt < 0) {
|
||||
char infobuff[256];
|
||||
_errno = errno;
|
||||
Error6("sendto(%d, %p, "F_Zu", 0, %s, "F_socklen"): %s",
|
||||
pipe->fd, buff, bytes,
|
||||
fd, buff, bytes,
|
||||
sockaddr_info(&pipe->peersa.soa, pipe->salen,
|
||||
infobuff, sizeof(infobuff)),
|
||||
pipe->salen, strerror(_errno));
|
||||
|
@ -102,7 +106,7 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
|
|||
if ((size_t)writt < bytes) {
|
||||
char infobuff[256];
|
||||
Warn7("sendto(%d, %p, "F_Zu", 0, %s, "F_socklen") only wrote "F_Zu" of "F_Zu" bytes",
|
||||
pipe->fd, buff, bytes,
|
||||
fd, buff, bytes,
|
||||
sockaddr_info(&pipe->peersa.soa, pipe->salen,
|
||||
infobuff, sizeof(infobuff)),
|
||||
pipe->salen, writt, bytes);
|
||||
|
@ -112,7 +116,7 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
|
|||
char infobuff[256];
|
||||
union sockaddr_union us;
|
||||
socklen_t uslen = sizeof(us);
|
||||
Getsockname(pipe->fd, &us.soa, &uslen);
|
||||
Getsockname(fd, &us.soa, &uslen);
|
||||
Notice1("local address: %s",
|
||||
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)));
|
||||
}
|
||||
|
@ -120,13 +124,14 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
|
|||
#endif /* WITH_SOCKET */
|
||||
|
||||
case XIOWRITE_PIPE:
|
||||
case XIOWRITE_2PIPE:
|
||||
do {
|
||||
writt = Write(pipe->para.bipipe.fdout, buff, bytes);
|
||||
writt = Write(fd, buff, bytes);
|
||||
} while (writt < 0 && errno == EINTR);
|
||||
_errno = errno;
|
||||
if (writt < 0) {
|
||||
Error4("write(%d, %p, "F_Zu"): %s",
|
||||
pipe->para.bipipe.fdout, buff, bytes, strerror(_errno));
|
||||
fd, buff, bytes, strerror(_errno));
|
||||
errno = _errno;
|
||||
return -1;
|
||||
}
|
||||
|
@ -136,22 +141,14 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
|
|||
}
|
||||
break;
|
||||
|
||||
case XIOWRITE_2PIPE:
|
||||
do {
|
||||
writt = Write(pipe->para.exec.fdout, buff, bytes);
|
||||
} while (writt < 0 && errno == EINTR);
|
||||
_errno = errno;
|
||||
if (writt < 0) {
|
||||
Error4("write(%d, %p, "F_Zu"): %s",
|
||||
pipe->para.exec.fdout, buff, bytes, strerror(_errno));
|
||||
errno = _errno;
|
||||
return -1;
|
||||
}
|
||||
if ((size_t)writt < bytes) {
|
||||
Warn2("write() only processed "F_Zu" of "F_Zu" bytes",
|
||||
writt, bytes);
|
||||
}
|
||||
break;
|
||||
#if WITH_TEST
|
||||
case XIOWRITE_TEST:
|
||||
/* this function prints its own error messages */
|
||||
return xiowrite_test(pipe, buff, bytes);
|
||||
case XIOWRITE_TESTREV:
|
||||
/* this function prints its own error messages */
|
||||
return xiowrite_testrev(pipe, buff, bytes);
|
||||
#endif /* WITH_TEST */
|
||||
|
||||
#if WITH_OPENSSL
|
||||
case XIOWRITE_OPENSSL:
|
||||
|
|
Loading…
Reference in a new issue