Output statistics per option and SIGUSR1

This commit is contained in:
Gerhard Rieger 2023-10-26 18:42:41 +02:00
parent 2af6089436
commit c2196d6f15
17 changed files with 304 additions and 26 deletions

View file

@ -41,6 +41,10 @@ Features:
references.
Test: VARS_IN_SNIFFPATH
Socat option --statistics logs final byte and packet counter values
before exit. Signal USR1 logs actual values.
Tests: OPTION_STATISTICS SIGUSR1_STATISTICS
Corrections:
When a sub process (EXEC, SYSTEM) terminated with exit code other than
0, its last sent data might have been lost depending on timing of read/

View file

@ -76,7 +76,7 @@ HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.
DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT doc/socat.yo 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 doc/socat-genericsocket.html
SHFILES = daemon.sh mail.sh ftp.sh readline.sh \
socat_buildscript_for_android.sh
TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \
TESTFILES = test.sh socks4echo.sh proxyecho.sh readline-test.sh \
proxy.sh socks4a-echo.sh
all: progs doc

View file

@ -672,6 +672,7 @@
#undef HAVE_GETGROUPLIST
#undef WITH_HELP
#undef WITH_STATS
#undef WITH_STDIO
#undef WITH_FDNUM
#undef WITH_FILE

View file

@ -163,6 +163,14 @@ AC_ARG_ENABLE(help, [ --disable-help disable help],
esac],
[AC_DEFINE(WITH_HELP) AC_MSG_RESULT(yes)])
AC_MSG_CHECKING(whether to include transfer statistics)
AC_ARG_ENABLE(stats, [ --disable-stats disable stats],
[case "$enableval" in
no) AC_MSG_RESULT(no);;
*) AC_DEFINE(WITH_STATS) AC_MSG_RESULT(yes);;
esac],
[AC_DEFINE(WITH_STATS) AC_MSG_RESULT(yes)])
AC_MSG_CHECKING(whether to include STDIO support)
AC_ARG_ENABLE(stdio, [ --disable-stdio disable STDIO support],
[case "$enableval" in

View file

@ -223,6 +223,11 @@ label(option_4)dit(bf(tt(-4)))
label(option_6)dit(bf(tt(-6)))
Use IP version 6 in case that the addresses do not implicitly or explicitly
specify a version.
label(option_statistics)dit(bf(tt(--statistics)))
Logs transfer statistics (bytes and blocks counters for both directions)
before terminating Socat.nl()
See also link(signal USR1)(signal_usr1).nl()
This feature is experimental and might change in future versions.
enddit()
@ -4057,6 +4062,16 @@ manpagefiles()
/usr/bin/procan
label(SIGNALS)
manpagesection(SIGNALS)
description(
label(signal_usr1)dit(SIGUSR1:) Causes logging of current transfer statistics.
nl()
See also link(option --statistics)(option_statistics)
)
label(ENVIRONMENT_VARIABLES)
manpagesection(ENVIRONMENT VARIABLES)

View file

@ -157,6 +157,9 @@ int procan(FILE *outfile) {
#endif
#ifdef SIZE_MAX
fprintf(outfile, "SIZE_MAX = %-24lu\n", SIZE_MAX);
#endif
#ifdef PIPE_BUF
fprintf(outfile, "PIPE_BUF = %-24d\n", PIPE_BUF);
#endif
}

104
socat.c
View file

@ -38,6 +38,7 @@ struct {
bool righttoleft; /* first addr wo, second addr ro */
xiolock_t lock; /* a lock file */
unsigned long log_sigs; /* signals to be caught just for logging */
bool statistics; /* log statistics on exit */
} socat_opts = {
8192, /* bufsiz */
false, /* verbose */
@ -52,6 +53,7 @@ struct {
false, /* righttoleft */
{ NULL, 0 }, /* lock */
1<<SIGHUP | 1<<SIGINT | 1<<SIGQUIT | 1<<SIGILL | 1<<SIGABRT | 1<<SIGBUS | 1<<SIGFPE | 1<<SIGSEGV | 1<<SIGTERM, /* log_sigs */
false /* statistics */
};
void socat_usage(FILE *fd);
@ -61,6 +63,7 @@ int socat(const char *address1, const char *address2);
int _socat(void);
int cv_newline(unsigned char *buff, ssize_t *bytes, int lineterm1, int lineterm2);
void socat_signal(int sig);
void socat_signal_logstats(int sig);
static int socat_sigchild(struct single *file);
void lftocrlf(char **in, ssize_t *len, size_t bufsiz);
@ -69,6 +72,7 @@ void crlftolf(char **in, ssize_t *len, size_t bufsiz);
static int socat_lock(void);
static void socat_unlock(void);
static int socat_newchild(void);
static void socat_print_stats(void);
static const char socatversion[] =
#include "./VERSION"
@ -323,6 +327,8 @@ int main(int argc, const char *argv[]) {
case '-':
if (!strcmp("experimental", &arg1[0][2])) {
xioparms.experimental = true;
} else if (!strcmp("statistics", &arg1[0][2])) {
socat_opts.statistics = true;
} else {
Error1("unknown option \"%s\"; use option \"-h\" for help", arg1[0]);
}
@ -374,7 +380,9 @@ int main(int argc, const char *argv[]) {
#endif /* WITH_MSGLEVEL <= E_DEBUG */
{
#if HAVE_SIGACTION
struct sigaction act;
#endif
int i, m;
sigfillset(&act.sa_mask); /* while in sighandler block all signals */
@ -383,9 +391,20 @@ int main(int argc, const char *argv[]) {
/* not sure which signals should be caught and print a message */
for (i = 0, m = 1; i < 8*sizeof(unsigned long); ++i, m <<= 1) {
if (socat_opts.log_sigs & m) {
#if HAVE_SIGACTION
Sigaction(i, &act, NULL);
#else
Signal(i, socat_signal);
#endif
}
}
#if HAVE_SIGACTION
act.sa_handler = socat_signal_logstats;
Sigaction(SIGUSR1, &act, NULL);
#else
Signal(SIGUSR1, socat_signal_logstats);
#endif
}
Signal(SIGPIPE, SIG_IGN);
@ -400,6 +419,9 @@ int main(int argc, const char *argv[]) {
}
Atexit(socat_unlock);
if (socat_opts.statistics) {
Atexit(socat_print_stats);
}
result = socat(arg1[0], arg1[1]);
if (result == EXIT_SUCCESS && engine_result != EXIT_SUCCESS) {
@ -428,6 +450,7 @@ void socat_usage(FILE *fd) {
fputs(" -D analyze file descriptors before loop\n", fd);
#endif
fputs(" --experimental enable experimental features\n", fd);
fputs(" --statistics output transfer statistics on exit\n", fd);
fputs(" -ly[facility] log to syslog, using facility (default is daemon)\n", fd);
fputs(" -lf<logfile> log to file\n", fd);
fputs(" -ls log to stderr (default if no other log)\n", fd);
@ -472,6 +495,16 @@ void socat_version(FILE *fd) {
fprintf(fd, " running on %s version %s, release %s, machine %s\n",
ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine);
fputs("features:\n", fd);
#ifdef WITH_HELP
fprintf(fd, " #define WITH_HELP %d\n", WITH_HELP);
#else
fputs(" #undef WITH_HELP\n", fd);
#endif
#ifdef WITH_STATS
fprintf(fd, " #define WITH_STATS %d\n", WITH_STATS);
#else
fputs(" #undef WITH_STATS\n", fd);
#endif
#ifdef WITH_STDIO
fprintf(fd, " #define WITH_STDIO %d\n", WITH_STDIO);
#else
@ -1339,6 +1372,10 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
}
if (bytes > 0) {
#if WITH_STATS
++XIO_RDSTREAM(inpipe)->blocks_read;
XIO_RDSTREAM(inpipe)->bytes_read += bytes;
#endif
/* handle escape char */
if (XIO_RDSTREAM(inpipe)->escape != -1) {
/* check input data for escape char */
@ -1490,6 +1527,10 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
} else {
Info3("transferred "F_Zu" bytes from %d to %d",
writt, XIO_GETRDFD(inpipe), XIO_GETWRFD(outpipe));
#if WITH_STATS
++XIO_WRSTREAM(outpipe)->blocks_written;
XIO_WRSTREAM(outpipe)->bytes_written += writt;
#endif
}
}
return writt;
@ -1671,3 +1712,66 @@ static int socat_newchild(void) {
havelock = false;
return 0;
}
#if WITH_STATS
void socat_signal_logstats(int signum) {
diag_in_handler = 1;
Notice1("socat_signal_logstats(): handling signal %d", signum);
socat_print_stats();
Notice1("socat_signal_logstats(): finishing signal %d", signum);
diag_in_handler = 0;
}
#endif /* WITH_STATS */
#if WITH_STATS
static void socat_print_stats(void)
{
const char ltorf0[] = "STATISTICS: left to right: %%%ullu packets(s), %%%ullu byte(s)";
const char rtolf0[] = "STATISTICS: right to left: %%%ullu packets(s), %%%ullu byte(s)";
char ltorf1[sizeof(ltorf0)]; /* final printf format with lengths of number */
char rtolf1[sizeof(rtolf0)]; /* final printf format with lengths of number */
unsigned int blocksd = 1, bytesd = 1; /* number of digits in output */
struct single *sock1w, *sock2w;
int savelevel;
if (sock1 == NULL || sock2 == NULL) {
Warn("transfer engine not yet started, statistics not available");
return;
}
if ((sock1->tag & ~XIO_TAG_CLOSED) == XIO_TAG_DUAL) {
sock1w = sock1->dual.stream[1];
} else {
sock1w = &sock1->stream;
}
if ((sock2->tag & ~XIO_TAG_CLOSED) == XIO_TAG_DUAL) {
sock2w = sock2->dual.stream[1];
} else {
sock2w = &sock2->stream;
}
if (!socat_opts.righttoleft && !socat_opts.righttoleft) {
/* Both directions - format output */
unsigned long long int maxblocks =
Max(sock1w->blocks_written, sock2w->blocks_written);
unsigned long long int maxbytes =
Max(sock1w->bytes_written, sock2w->bytes_written);
/* Calculate number of digits */
while (maxblocks >= 10) { ++blocksd; maxblocks /= 10; }
while (maxbytes >= 10) { ++bytesd; maxbytes /= 10; }
}
snprintf(ltorf1, sizeof(ltorf1), ltorf0, blocksd, bytesd);
snprintf(rtolf1, sizeof(rtolf1), rtolf0, blocksd, bytesd);
/* Statistics are E_INFO level; make sure they are printed anyway */
savelevel = diag_get_int('d');
diag_set_int('d', E_INFO);
Warn("statistics are experimental");
if (!socat_opts.righttoleft) {
Info2(ltorf1, sock2w->blocks_written, sock2w->bytes_written);
}
if (!socat_opts.lefttoright) {
Info2(rtolf1, sock1w->blocks_written, sock1w->bytes_written);
}
diag_set_int('d', savelevel);
return;
}
#endif /* WITH_STATs */

143
test.sh
View file

@ -278,7 +278,7 @@ tolower () {
psleep () {
local T="$1"
[ "$T" = 0 ] && T=0.000002
$SOCAT -T "$T" pipe pipe
$SOCAT -T "$T" pipe pipe 2>/dev/null
}
# time in microseconds to wait in some situations
if ! type usleep >/dev/null 2>&1 ||
@ -289,7 +289,7 @@ if ! type usleep >/dev/null 2>&1 ||
*???????) S="${n%??????}"; uS="${n:${#n}-6}" ;;
*) S=0; uS="00000$n"; uS="${uS:${#uS}-6}" ;;
esac
$SOCAT -T "$S.$uS" pipe pipe
$SOCAT -T "$S.$uS" pipe pipe 2>/dev/null
}
fi
#USLEEP=usleep
@ -974,6 +974,12 @@ runssctp6 () {
return 0;
}
# check if UNIX domain sockets work
runsunix () {
# for now...
return 0;
}
# wait until an IP4 protocol is ready
waitip4proto () {
local proto="$1"
@ -13399,7 +13405,7 @@ N=$((N+1))
# Test the OpenSSL SNI feature
NAME=OPENSSL_SNI
case "$TESTS" in
*%$N%*|*%functions%*|*%socket%*|*%openssl%*|*%$NAME%*)
*%$N%*|*%functions%*|*%socket%*|*%openssl%*|*%foreign%*|*%$NAME%*)
TEST="$NAME: Test the OpenSSL SNI feature"
# Connect to a server that is known to use SNI. Use an SNI name, not the
# certifications default name. When the TLS connection is established
@ -13446,7 +13452,7 @@ N=$((N+1))
# Test the openssl-no-sni option
NAME=OPENSSL_NO_SNI
case "$TESTS" in
*%$N%*|*%functions%*|*%socket%*|*%openssl%*|*%$NAME%*)
*%$N%*|*%functions%*|*%socket%*|*%openssl%*|*%foreign%*|*%$NAME%*)
TEST="$NAME: Test the openssl-no-sni option"
# Connect to a server that is known to use SNI. Use an SNI name, not the
# certifications default name, and use option openssl-no-sni.
@ -14498,7 +14504,7 @@ CMD="$TRACE $SOCAT $opts -d -d -d -d /dev/null UDP4-SENDTO:$LOCALHOST:$PORT,lowp
printf "test $F_n $TEST... " $N
$CMD >/dev/null 2>"${te}"
rc1=$?
LOWPORT=$(grep 'D bind(.*:' $te |sed 's/.*:\([0-9][0-9]*\),.*/\1/')
LOWPORT=$(grep '[DE] bind(.*:' $te |sed 's/.*:\([0-9][0-9]*\),.*/\1/')
#echo "LOWPORT=\"$LOWPORT\"" >&2
#type socat >&2
if [[ $LOWPORT =~ [0-9][0-9]* ]] && [ "$LOWPORT" -ge 640 -a "$LOWPORT" -le 1023 ]; then
@ -14966,7 +14972,6 @@ N=$((N+1))
while read KEYW FEAT RUNS ADDR IPPORT; do
if [ -z "$KEYW" ] || [[ "$KEYW" == \#* ]]; then continue; fi
RUNS=$(tolower $KEYW)
PROTO=$KEYW
proto="$(echo "$PROTO" |tr A-Z a-z)"
feat="$(tolower "$FEAT")"
@ -15054,8 +15059,8 @@ fi # NUMCOND
esac
N=$((N+1))
done <<<"
UDP4 UDP udp4 127.0.0.1 PORT
UDP6 UDP udp4 [::1] PORT
UDP4 UDP ip4 127.0.0.1 PORT
UDP6 UDP ip6 [::1] PORT
UNIX unix unix $td/test\$N.server -
"
@ -15395,6 +15400,127 @@ esac
N=$((N+1))
# Test logging of statistics on Socat option --statistics
NAME=OPTION_STATISTICS
case "$TESTS" in
*%$N%*|*%functions%*|*%stats%*|*%system%*|*%stdio%*|*%$NAME%*)
TEST="$NAME: Socat option --statistics"
# Invoke Socat with option --statistics, transfer some date, and check the log
# file for the values
if ! eval $NUMCOND; then :;
elif ! $(type >/dev/null 2>&1); then
$PRINTF "test $F_n $TEST... ${YELLOW}tee not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! F=$(testfeats STATS STDIO SYSTEM); then
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! A=$(testaddrs STDIO SYSTEM); then
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! o=$(testoptions pty cfmakeraw) >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"
CMD0="$TRACE $SOCAT $opts --statistics STDIO SYSTEM:'tee /dev/stdout',pty,cfmakeraw"
printf "test $F_n $TEST... " $N
echo "$da" |eval "$CMD0" >"${tf}0" 2>"${te}0"
rc0=$?
if [ $rc0 -ne 0 ]; then
# The test could not run meaningfully
$PRINTF "$CANT\n"
if [ "$VERBOSE" ]; then echo "$CMD0"; fi
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif [ $(grep STATISTICS "${te}0" |wc -l) -eq 2 ]; then
$PRINTF "$OK\n"
if [ "$VERBOSE" ]; then echo "$CMD0"; fi
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
numOK=$((numOK+1))
else
$PRINTF "$FAILED\n"
echo "$CMD0 &"
cat "${te}0" >&2
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
namesFAIL="$namesFAIL $NAME"
fi
fi # NUMCOND
;;
esac
N=$((N+1))
# Test logging of statistics on SIGUSR1
NAME=SIGUSR1_STATISTICS
case "$TESTS" in
*%$N%*|*%functions%*|*%signal%*|*%stats%*|*%system%*|*%stdio%*|*%$NAME%*)
TEST="$NAME: statistics on SIGUSR1"
# Invoke Socat without option --statistics, transfer some date, send signal
# USR1,and check the log file for the values
if ! eval $NUMCOND; then :;
elif ! $(type tee >/dev/null 2>&1); then
$PRINTF "test $F_n $TEST... ${YELLOW}tee not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! $(type pkill >/dev/null 2>&1); then
$PRINTF "test $F_n $TEST... ${YELLOW}pkill not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! F=$(testfeats STATS STDIO SYSTEM); then
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! A=$(testaddrs STDIO SYSTEM); then
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! o=$(testoptions pty cfmakeraw) >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"
CMD0="$TRACE $SOCAT $opts STDIO SYSTEM:'tee /dev/stdout 2>/dev/null',pty,cfmakeraw"
#set -vx
printf "test $F_n $TEST... " $N
{ echo "$da"; relsleep 3; } |eval "$CMD0" >"${tf}0" 2>"${te}0" &
pid0=$!
relsleep 2
TTY=$(tty |sed 's|/dev/||')
pkill -USR1 -t $TTY socat || { echo "pkill -t $TTY -USR1 socat"; }
relsleep 1
pkill -t $TTY socat
wait
if [ "$(grep STATISTICS "${te}0" |wc -l)" -eq 2 ]; then
$PRINTF "$OK\n"
if [ "$VERBOSE" ]; then echo "$CMD0"; fi
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
numOK=$((numOK+1))
else
$PRINTF "$FAILED\n"
echo "$CMD0 &"
cat "${te}0" >&2
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
namesFAIL="$namesFAIL $NAME"
fi
fi # NUMCOND
;;
esac
N=$((N+1))
# end of common tests
##################################################################################
@ -15528,6 +15654,7 @@ exit
NAME=SHORT_UNIQUE_TESTNAME
case "$TESTS" in
*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%$NAME%*)
#*%foreign%*|*%root%*|*%listen%*|*%fork%*|*%ip4%*|*%tcp4%*|*%bug%*|...
TEST="$NAME: give a one line description of test"
# Describe how the test is performed, and what's the success criteria
if ! eval $NUMCOND; then :;

View file

@ -197,7 +197,10 @@ int _xioopen_open(const char *path, int rw, struct opt *opts) {
retropt_modet(opts, OPT_PERM, &mode);
if ((fd = Open(path, flags, mode)) < 0) {
do {
fd = Open(path, flags, mode);
} while (fd < 0 && errno == EINTR);
if (fd < 0) {
Error4("open(\"%s\", 0%lo, 0%03o): %s",
path, flags, mode, strerror(errno));
return STAT_RETRYLATER;

View file

@ -153,7 +153,7 @@ static int xioopen_fifo(int argc, const char *argv[], struct opt *opts, int xiof
}
} else {
/* exists */
Debug1("xioopen_fifo(\"%s\"): already exist, opening it", pipename);
Info1("xioopen_fifo(\"%s\"): already exist, opening it", pipename);
Notice3("opening %s \"%s\" for %s",
filetypenames[(pipstat.st_mode&S_IFMT)>>12],
pipename, ddirection[rw]);

9
xio.h
View file

@ -85,8 +85,9 @@ enum xiotag {
XIO_TAG_RDONLY, /* this is a single read-only stream */
XIO_TAG_WRONLY, /* this is a single write-only stream */
XIO_TAG_RDWR, /* this is a single read-write stream */
XIO_TAG_DUAL /* this is a dual stream, consisting of two single
XIO_TAG_DUAL, /* this is a dual stream, consisting of two single
streams */
XIO_TAG_CLOSED=8, /* close, additional bit */
} ;
/* Keep condition consistent with xioopts.h:GROUP_*! */
@ -278,6 +279,12 @@ typedef struct single {
} tun;
#endif /* WITH_TUN */
} para;
#if WITH_STATS
unsigned long long blocks_read;
unsigned long long bytes_read;
unsigned long long blocks_written;
unsigned long long bytes_written;
#endif /* WITH_STATS */
} xiosingle_t;
/* rw: 0..read, 1..write, 2..r/w */

View file

@ -93,7 +93,7 @@ int xioclose1(struct single *pipe) {
free(pipe->unlink_close);
}
pipe->tag = XIO_TAG_INVALID;
pipe->tag |= XIO_TAG_CLOSED;
return 0; /*! */
}
@ -111,7 +111,7 @@ int xioclose(xiofile_t *file) {
if (file->tag == XIO_TAG_DUAL) {
result = xioclose1(file->dual.stream[0]);
result |= xioclose1(file->dual.stream[1]);
file->tag = XIO_TAG_INVALID;
file->tag |= XIO_TAG_CLOSED;
} else {
result = xioclose1(&file->stream);
}

View file

@ -18,7 +18,8 @@ void xioexit(void) {
diag_in_handler = 0;
Debug("starting xioexit()");
for (i = 0; i < XIO_MAXSOCK; ++i) {
if (sock[i] != NULL && sock[i]->tag != XIO_TAG_INVALID) {
if (sock[i] != NULL && sock[i]->tag != XIO_TAG_INVALID &&
!(sock[i]->tag & XIO_TAG_CLOSED)) {
xioclose(sock[i]);
}
}

View file

@ -121,22 +121,27 @@ void xiodroplocks(void) {
int i;
for (i = 0; i < XIO_MAXSOCK; ++i) {
if (sock[i] != NULL && sock[i]->tag != XIO_TAG_INVALID) {
if (sock[i] != NULL && sock[i]->tag != XIO_TAG_INVALID &&
!(sock[i]->tag & XIO_TAG_CLOSED)) {
xiofiledroplock(sock[i]);
}
}
}
/* 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
/* Consider an invocation 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
better if it survives all sub processes. Thus, it must not be killed when
the sub process delivers EOF. Also, a socket that is reused in sub processes
should not be shut down (affects the connection), but closed (affects only
sub processes copy of file descriptor) */
static int xio_nokill(xiofile_t *sock) {
int result = 0;
if (sock->tag & XIO_TAG_CLOSED) {
return -1;
}
switch (sock->tag) {
case XIO_TAG_INVALID:
default:

View file

@ -23,7 +23,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
struct single *pipe;
int _errno;
if (file->tag == XIO_TAG_INVALID) {
if (file->tag == XIO_TAG_INVALID || file->tag & XIO_TAG_CLOSED) {
Error1("xioread(): invalid xiofile descriptor %p", file);
errno = EINVAL;
return -1;
@ -31,7 +31,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
if (file->tag == XIO_TAG_DUAL) {
pipe = file->dual.stream[0];
if (pipe->tag == XIO_TAG_INVALID) {
if (pipe->tag == XIO_TAG_INVALID || file->tag & XIO_TAG_CLOSED) {
Error1("xioread(): invalid xiofile sub descriptor %p[0]", file);
errno = EINVAL;
return -1;
@ -433,7 +433,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
ssize_t xiopending(xiofile_t *file) {
struct single *pipe;
if (file->tag == XIO_TAG_INVALID) {
if (file->tag == XIO_TAG_INVALID || file->tag & XIO_TAG_CLOSED) {
Error1("xiopending(): invalid xiofile descriptor %p", file);
errno = EINVAL;
return -1;
@ -441,7 +441,7 @@ ssize_t xiopending(xiofile_t *file) {
if (file->tag == XIO_TAG_DUAL) {
pipe = file->dual.stream[0];
if (pipe->tag == XIO_TAG_INVALID) {
if (pipe->tag == XIO_TAG_INVALID || file->tag & XIO_TAG_CLOSED) {
Error1("xiopending(): invalid xiofile sub descriptor %p[0]", file);
errno = EINVAL;
return -1;

View file

@ -25,7 +25,7 @@ static void signal_kill_pid(int dummy) {
int xioshutdown(xiofile_t *sock, int how) {
int result = 0;
if (sock->tag == XIO_TAG_INVALID) {
if (sock->tag == XIO_TAG_INVALID || sock->tag & XIO_TAG_CLOSED) {
Error("xioshutdown(): invalid file descriptor");
errno = EINVAL;
return -1;

View file

@ -22,7 +22,7 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
struct single *pipe;
int _errno;
if (file->tag == XIO_TAG_INVALID) {
if (file->tag == XIO_TAG_INVALID || file->tag & XIO_TAG_CLOSED) {
Error1("xiowrite(): invalid xiofile descriptor %p", file);
errno = EINVAL;
return -1;
@ -30,7 +30,7 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
if (file->tag == XIO_TAG_DUAL) {
pipe = file->dual.stream[1];
if (pipe->tag == XIO_TAG_INVALID) {
if (pipe->tag == XIO_TAG_INVALID || file->tag & XIO_TAG_CLOSED) {
Error1("xiowrite(): invalid xiofile sub descriptor %p[1]", file);
errno = EINVAL;
return -1;