mirror of
https://github.com/moparisthebest/socat
synced 2024-12-21 22:48:48 -05:00
new address options shut-null, null-eof
This commit is contained in:
parent
793763677a
commit
806bccbf94
10
CHANGES
10
CHANGES
@ -1,7 +1,13 @@
|
|||||||
|
|
||||||
new features:
|
new features:
|
||||||
new address options shut-none, shut-down, and shut-close allow to
|
address options shut-none, shut-down, and shut-close allow to control
|
||||||
control socat's half close behaviour
|
socat's half close behaviour
|
||||||
|
|
||||||
|
with address option shut-null socat sends an empty packet to the peer
|
||||||
|
to indicate EOF
|
||||||
|
|
||||||
|
option null-eof changes the behaviour of sockets that receive an empty
|
||||||
|
packet to see EOF instead of ignoring it
|
||||||
|
|
||||||
####################### V 1.7.0.1:
|
####################### V 1.7.0.1:
|
||||||
|
|
||||||
|
10
doc/socat.yo
10
doc/socat.yo
@ -1490,6 +1490,16 @@ label(OPTION_SHUT_DOWN)dit(bf(tt(shut-down)))
|
|||||||
label(OPTION_SHUT_CLOSE)dit(bf(tt(shut-close)))
|
label(OPTION_SHUT_CLOSE)dit(bf(tt(shut-close)))
|
||||||
Changes the (address dependent) method of shutting down the write part of a
|
Changes the (address dependent) method of shutting down the write part of a
|
||||||
connection to tt(close\(fd)).
|
connection to tt(close\(fd)).
|
||||||
|
label(OPTION_SHUT_NULL)dit(bf(tt(shut-null)))
|
||||||
|
When one address indicates EOF, socat() will send a zero sized packet to the
|
||||||
|
write channel of the other address to transfer the EOF condition. This is
|
||||||
|
useful with UDP and other datagram protocols. Has been tested against
|
||||||
|
netcat and socat with option link(null-eof)(OPTION_NULL_EOF).
|
||||||
|
label(OPTION_NULL_EOF)dit(bf(tt(null-eof)))
|
||||||
|
Normally socat() will ignore empty (zero size payload) packets arriving on
|
||||||
|
datagram sockets, so it survives port scans. With this option socat()
|
||||||
|
interprets empty datagram packets as EOF indicator (see
|
||||||
|
link(shut-null)(OPTION_SHUT_NULL).
|
||||||
label(OPTION_IOCTL_VOID)dit(bf(tt(ioctl-void=<request>)))
|
label(OPTION_IOCTL_VOID)dit(bf(tt(ioctl-void=<request>)))
|
||||||
Calls tt(ioctl()) with the request value as second argument and NULL as
|
Calls tt(ioctl()) with the request value as second argument and NULL as
|
||||||
third argument. This option allows to utilize ioctls that are not
|
third argument. This option allows to utilize ioctls that are not
|
||||||
|
52
test.sh
52
test.sh
@ -7558,6 +7558,58 @@ esac
|
|||||||
N=$((N+1))
|
N=$((N+1))
|
||||||
|
|
||||||
|
|
||||||
|
# test the shut-null and null-eof options
|
||||||
|
NAME=SHUTNULLEOF
|
||||||
|
case "$TESTS" in
|
||||||
|
*%functions%*|*%socket%*|*%$NAME%*)
|
||||||
|
TEST="$NAME: options shut-null and null-eof"
|
||||||
|
# run a receiving background process with option null-eof.
|
||||||
|
# start a sending process with option shut-null that sends a test record to the
|
||||||
|
# receiving process and then terminates.
|
||||||
|
# send another test record.
|
||||||
|
# whe the receiving process just got the first test record the test succeeded
|
||||||
|
if ! eval $NUMCOND; then :; else
|
||||||
|
tf="$td/test$N.stout"
|
||||||
|
te="$td/test$N.stderr"
|
||||||
|
tdiff="$td/test$N.diff"
|
||||||
|
da="test$N $(date) $RANDOM"
|
||||||
|
CMD0="$SOCAT $opts -u UDP-RECV:$PORT,null-eof CREAT:$tf"
|
||||||
|
CMD1="$SOCAT $opts -u - UDP-SENDTO:127.0.0.1:$PORT,shut-null"
|
||||||
|
printf "test $F_n $TEST... " $N
|
||||||
|
$CMD0 >/dev/null 2>"${te}0" &
|
||||||
|
pid0=$!
|
||||||
|
waitudp4port $PORT 1
|
||||||
|
echo "$da" |$CMD1 >"${tf}1" 2>"${te}1"
|
||||||
|
rc1=$?
|
||||||
|
echo "xyz" |$CMD1 >"${tf}2" 2>"${te}2"
|
||||||
|
rc2=$?
|
||||||
|
kill $pid0 2>/dev/null; wait
|
||||||
|
if [ $rc1 != 0 -o $rc2 != 0 ]; then
|
||||||
|
$PRINTF "$FAILED\n"
|
||||||
|
echo "$CMD0 &"
|
||||||
|
echo "$CMD1"
|
||||||
|
cat "${te}0"
|
||||||
|
cat "${te}1"
|
||||||
|
cat "${te}2"
|
||||||
|
numFAIL=$((numFAIL+1))
|
||||||
|
elif echo "$da" |diff - "${tf}" >"$tdiff"; then
|
||||||
|
$PRINTF "$OK\n"
|
||||||
|
numOK=$((numOK+1))
|
||||||
|
else
|
||||||
|
$PRINTF "$FAILED\n"
|
||||||
|
echo "$CMD0 &"
|
||||||
|
echo "$CMD1"
|
||||||
|
cat "${te}0"
|
||||||
|
cat "${te}1"
|
||||||
|
cat "${tdiff}"
|
||||||
|
numFAIL=$((numFAIL+1))
|
||||||
|
fi
|
||||||
|
fi # NUMCOND
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
N=$((N+1))
|
||||||
|
|
||||||
|
|
||||||
NAME=UDP6LISTENBIND
|
NAME=UDP6LISTENBIND
|
||||||
# this tests for a bug in (up to) 1.5.0.0:
|
# this tests for a bug in (up to) 1.5.0.0:
|
||||||
# with udp*-listen, the bind option supported only IPv4
|
# with udp*-listen, the bind option supported only IPv4
|
||||||
|
1
xio-fd.c
1
xio-fd.c
@ -78,6 +78,7 @@ const struct optdesc opt_end_close = { "end-close", "close", OPT_END_CLOSE, GROU
|
|||||||
const struct optdesc opt_shut_none = { "shut-none", NULL, OPT_SHUT_NONE, GROUP_FD, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoshut, XIOSHUT_NONE };
|
const struct optdesc opt_shut_none = { "shut-none", NULL, OPT_SHUT_NONE, GROUP_FD, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoshut, XIOSHUT_NONE };
|
||||||
const struct optdesc opt_shut_down = { "shut-down", NULL, OPT_SHUT_DOWN, GROUP_FD, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoshut, XIOSHUT_DOWN };
|
const struct optdesc opt_shut_down = { "shut-down", NULL, OPT_SHUT_DOWN, GROUP_FD, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoshut, XIOSHUT_DOWN };
|
||||||
const struct optdesc opt_shut_close= { "shut-close", NULL, OPT_SHUT_CLOSE, GROUP_FD, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoshut, XIOSHUT_CLOSE };
|
const struct optdesc opt_shut_close= { "shut-close", NULL, OPT_SHUT_CLOSE, GROUP_FD, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoshut, XIOSHUT_CLOSE };
|
||||||
|
const struct optdesc opt_shut_null = { "shut-null", NULL, OPT_SHUT_NULL, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoshut, XIOSHUT_NULL };
|
||||||
|
|
||||||
/****** generic ioctl() options ******/
|
/****** generic ioctl() options ******/
|
||||||
const struct optdesc opt_ioctl_void = { "ioctl-void", "ioctl", OPT_IOCTL_VOID, GROUP_FD, PH_FD, TYPE_INT, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
|
const struct optdesc opt_ioctl_void = { "ioctl-void", "ioctl", OPT_IOCTL_VOID, GROUP_FD, PH_FD, TYPE_INT, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
|
||||||
|
1
xio-fd.h
1
xio-fd.h
@ -45,6 +45,7 @@ extern const struct optdesc opt_end_close;
|
|||||||
extern const struct optdesc opt_shut_none;
|
extern const struct optdesc opt_shut_none;
|
||||||
extern const struct optdesc opt_shut_down;
|
extern const struct optdesc opt_shut_down;
|
||||||
extern const struct optdesc opt_shut_close;
|
extern const struct optdesc opt_shut_close;
|
||||||
|
extern const struct optdesc opt_shut_null;
|
||||||
extern const struct optdesc opt_streams_i_push;
|
extern const struct optdesc opt_streams_i_push;
|
||||||
|
|
||||||
#endif /* !defined(__xio_fd_h_included) */
|
#endif /* !defined(__xio_fd_h_included) */
|
||||||
|
@ -196,6 +196,8 @@ const struct optdesc opt_setsockopt_int = { "setsockopt-int", "sockopt-int
|
|||||||
const struct optdesc opt_setsockopt_bin = { "setsockopt-bin", "sockopt-bin", OPT_SETSOCKOPT_BIN, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_BIN, OFUNC_SOCKOPT_GENERIC, 0, 0 };
|
const struct optdesc opt_setsockopt_bin = { "setsockopt-bin", "sockopt-bin", OPT_SETSOCKOPT_BIN, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_BIN, OFUNC_SOCKOPT_GENERIC, 0, 0 };
|
||||||
const struct optdesc opt_setsockopt_string = { "setsockopt-string", "sockopt-string", OPT_SETSOCKOPT_STRING, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_STRING, OFUNC_SOCKOPT_GENERIC, 0, 0 };
|
const struct optdesc opt_setsockopt_string = { "setsockopt-string", "sockopt-string", OPT_SETSOCKOPT_STRING, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_STRING, OFUNC_SOCKOPT_GENERIC, 0, 0 };
|
||||||
|
|
||||||
|
const struct optdesc opt_null_eof = { "null-eof", NULL, OPT_NULL_EOF, GROUP_SOCKET, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.para.socket.null_eof };
|
||||||
|
|
||||||
|
|
||||||
#if WITH_GENERICSOCKET
|
#if WITH_GENERICSOCKET
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* source: xio-socket.h */
|
/* source: xio-socket.h */
|
||||||
/* Copyright Gerhard Rieger 2001-2008 */
|
/* Copyright Gerhard Rieger 2001-2009 */
|
||||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||||
|
|
||||||
#ifndef __xio_socket_h_included
|
#ifndef __xio_socket_h_included
|
||||||
@ -67,6 +67,7 @@ extern const struct optdesc opt_protocol_family;
|
|||||||
extern const struct optdesc opt_setsockopt_int;
|
extern const struct optdesc opt_setsockopt_int;
|
||||||
extern const struct optdesc opt_setsockopt_bin;
|
extern const struct optdesc opt_setsockopt_bin;
|
||||||
extern const struct optdesc opt_setsockopt_string;
|
extern const struct optdesc opt_setsockopt_string;
|
||||||
|
extern const struct optdesc opt_null_eof;
|
||||||
|
|
||||||
|
|
||||||
extern
|
extern
|
||||||
|
7
xio.h
7
xio.h
@ -147,10 +147,11 @@ typedef struct single {
|
|||||||
char *unlink_close; /* name of a symlink or unix socket to be removed */
|
char *unlink_close; /* name of a symlink or unix socket to be removed */
|
||||||
int dtype;
|
int dtype;
|
||||||
enum {
|
enum {
|
||||||
XIOSHUT_UNSPEC, /* fall back to old (up to 1.7.0.0) behaviour */
|
XIOSHUT_UNSPEC, /* standard (address dependent) behaviour */
|
||||||
XIOSHUT_NONE, /* do nothing on shutdown */
|
XIOSHUT_NONE, /* do nothing on shutdown */
|
||||||
XIOSHUT_CLOSE, /* close the FD */
|
XIOSHUT_CLOSE, /* close the FD */
|
||||||
XIOSHUT_DOWN /* shutdown() */
|
XIOSHUT_DOWN, /* shutdown() */
|
||||||
|
XIOSHUT_NULL /* send an empty packet (dgram socket) */
|
||||||
} howtoshut;
|
} howtoshut;
|
||||||
enum {
|
enum {
|
||||||
END_UNSPEC, /* after init, when no end-close... option */
|
END_UNSPEC, /* after init, when no end-close... option */
|
||||||
@ -183,7 +184,7 @@ typedef struct single {
|
|||||||
struct {
|
struct {
|
||||||
struct timeval connect_timeout; /* how long to hang in connect() */
|
struct timeval connect_timeout; /* how long to hang in connect() */
|
||||||
union sockaddr_union la; /* local socket address */
|
union sockaddr_union la; /* local socket address */
|
||||||
bool emptyiseof; /* with dgram: empty packet means EOF */
|
bool null_eof; /* with dgram: empty packet means EOF */
|
||||||
bool dorange;
|
bool dorange;
|
||||||
struct xiorange range; /* restrictions for peer address */
|
struct xiorange range; /* restrictions for peer address */
|
||||||
#if _WITH_IP4 || _WITH_IP6
|
#if _WITH_IP4 || _WITH_IP6
|
||||||
|
@ -926,6 +926,7 @@ const struct optname optionnames[] = {
|
|||||||
#ifdef O_NSHARE
|
#ifdef O_NSHARE
|
||||||
IF_OPEN ("nshare", &opt_o_nshare)
|
IF_OPEN ("nshare", &opt_o_nshare)
|
||||||
#endif
|
#endif
|
||||||
|
IF_SOCKET ("null-eof", &opt_null_eof)
|
||||||
#ifdef O_ASYNC
|
#ifdef O_ASYNC
|
||||||
IF_ANY ("o-async", &opt_async)
|
IF_ANY ("o-async", &opt_async)
|
||||||
#endif
|
#endif
|
||||||
@ -1316,6 +1317,7 @@ const struct optname optionnames[] = {
|
|||||||
IF_ANY ("shut-close", &opt_shut_close)
|
IF_ANY ("shut-close", &opt_shut_close)
|
||||||
IF_ANY ("shut-down", &opt_shut_down)
|
IF_ANY ("shut-down", &opt_shut_down)
|
||||||
IF_ANY ("shut-none", &opt_shut_none)
|
IF_ANY ("shut-none", &opt_shut_none)
|
||||||
|
IF_ANY ("shut-null", &opt_shut_null)
|
||||||
#if WITH_EXEC || WITH_SYSTEM
|
#if WITH_EXEC || WITH_SYSTEM
|
||||||
IF_ANY ("sid", &opt_setsid)
|
IF_ANY ("sid", &opt_setsid)
|
||||||
#endif
|
#endif
|
||||||
|
@ -444,6 +444,7 @@ enum e_optcode {
|
|||||||
OPT_NOFLSH, /* termios.c_lflag */
|
OPT_NOFLSH, /* termios.c_lflag */
|
||||||
OPT_NOFORK, /* exec, system */
|
OPT_NOFORK, /* exec, system */
|
||||||
OPT_NOPROMPT, /* readline */
|
OPT_NOPROMPT, /* readline */
|
||||||
|
OPT_NULL_EOF, /* receiving empty packet triggers EOF */
|
||||||
#ifdef OCRNL
|
#ifdef OCRNL
|
||||||
OPT_OCRNL, /* termios.c_oflag */
|
OPT_OCRNL, /* termios.c_oflag */
|
||||||
#endif
|
#endif
|
||||||
@ -593,6 +594,7 @@ enum e_optcode {
|
|||||||
OPT_SHUT_CLOSE,
|
OPT_SHUT_CLOSE,
|
||||||
OPT_SHUT_DOWN,
|
OPT_SHUT_DOWN,
|
||||||
OPT_SHUT_NONE,
|
OPT_SHUT_NONE,
|
||||||
|
OPT_SHUT_NULL, /* send 0 bytes on shutdown */
|
||||||
OPT_SIGHUP,
|
OPT_SIGHUP,
|
||||||
OPT_SIGINT,
|
OPT_SIGINT,
|
||||||
OPT_SIGQUIT,
|
OPT_SIGQUIT,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* source: xioread.c */
|
/* source: xioread.c */
|
||||||
/* Copyright Gerhard Rieger 2001-2008 */
|
/* Copyright Gerhard Rieger 2001-2009 */
|
||||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||||
|
|
||||||
/* this is the source of the extended read function */
|
/* this is the source of the extended read function */
|
||||||
@ -159,7 +159,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||||||
bytes,
|
bytes,
|
||||||
sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)));
|
sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)));
|
||||||
if (bytes == 0) {
|
if (bytes == 0) {
|
||||||
if (!pipe->para.socket.emptyiseof) {
|
if (!pipe->para.socket.null_eof) {
|
||||||
errno = EAGAIN; return -1;
|
errno = EAGAIN; return -1;
|
||||||
}
|
}
|
||||||
return bytes;
|
return bytes;
|
||||||
@ -350,7 +350,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||||||
bytes,
|
bytes,
|
||||||
sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)));
|
sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)));
|
||||||
if (bytes == 0) {
|
if (bytes == 0) {
|
||||||
if (!pipe->para.socket.emptyiseof) {
|
if (!pipe->para.socket.null_eof) {
|
||||||
errno = EAGAIN; return -1;
|
errno = EAGAIN; return -1;
|
||||||
}
|
}
|
||||||
return bytes;
|
return bytes;
|
||||||
|
@ -35,6 +35,7 @@ int xioshutdown(xiofile_t *sock, int how) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (sock->stream.howtoshut) {
|
switch (sock->stream.howtoshut) {
|
||||||
|
char writenull;
|
||||||
case XIOSHUT_NONE:
|
case XIOSHUT_NONE:
|
||||||
return 0;
|
return 0;
|
||||||
case XIOSHUT_CLOSE:
|
case XIOSHUT_CLOSE:
|
||||||
@ -49,9 +50,16 @@ int xioshutdown(xiofile_t *sock, int how) {
|
|||||||
sock->stream.fd, how, strerror(errno));
|
sock->stream.fd, how, strerror(errno));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
#if _WITH_SOCKET
|
||||||
|
case XIOSHUT_NULL:
|
||||||
|
/* send an empty packet; only useful on datagram sockets? */
|
||||||
|
xiowrite(sock, &writenull, 0);
|
||||||
|
return 0;
|
||||||
|
#endif /* _WITH_SOCKET */
|
||||||
default: ;
|
default: ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if WITH_OPENSSL
|
#if WITH_OPENSSL
|
||||||
if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_OPENSSL) {
|
if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_OPENSSL) {
|
||||||
sycSSL_shutdown (sock->stream.para.openssl.ssl);
|
sycSSL_shutdown (sock->stream.para.openssl.ssl);
|
||||||
|
Loading…
Reference in New Issue
Block a user