mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
Output statistics per option and SIGUSR1
This commit is contained in:
parent
2af6089436
commit
c2196d6f15
17 changed files with 304 additions and 26 deletions
4
CHANGES
4
CHANGES
|
@ -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/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -672,6 +672,7 @@
|
|||
#undef HAVE_GETGROUPLIST
|
||||
|
||||
#undef WITH_HELP
|
||||
#undef WITH_STATS
|
||||
#undef WITH_STDIO
|
||||
#undef WITH_FDNUM
|
||||
#undef WITH_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
|
||||
|
|
15
doc/socat.yo
15
doc/socat.yo
|
@ -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)
|
||||
|
||||
|
|
3
procan.c
3
procan.c
|
@ -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
104
socat.c
|
@ -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
143
test.sh
|
@ -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 :;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
9
xio.h
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue