in ignoreeof mode socat also blocked data transfer in the other direction

This commit is contained in:
Gerhard Rieger 2008-09-19 09:03:59 +02:00
parent f8496421f9
commit 0e1eb7e4b4
4 changed files with 111 additions and 47 deletions

View File

@ -22,6 +22,10 @@ corrections:
additional empty arguments (thanks to Olivier Hervieu for reporting
this bug)
in ignoreeof polling mode socat also blocked data transfer in the other
direction during the 1s wait intervalls (thanks to Jorgen Cederlof for
reporting this bug)
corrected alphabetical order of options (proxy-auth)
some minor corrections

View File

@ -1 +1 @@
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont"
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock"

51
socat.c
View File

@ -760,10 +760,6 @@ int _socat(void) {
/* for ignoreeof */
if (polling) {
if (!wasaction) {
/* yes we could do it with poll but I like readable trace output */
if (socat_opts.pollintv.tv_sec) Sleep(socat_opts.pollintv.tv_sec);
if (socat_opts.pollintv.tv_usec) Usleep(socat_opts.pollintv.tv_usec);
if (socat_opts.total_timeout.tv_sec != 0 ||
socat_opts.total_timeout.tv_usec != 0) {
if (total_timeout.tv_usec < socat_opts.pollintv.tv_usec) {
@ -804,6 +800,7 @@ int _socat(void) {
closing = 2;
}
/* frame 1: set the poll parameters and loop over poll() EINTR) */
do { /* loop over poll() EINTR */
int _errno;
@ -817,11 +814,20 @@ int _socat(void) {
closing = 2;
}
/* now the fds are assigned */
/* use the ignoreeof timeout if appropriate */
if (polling) {
int ptimeout = 1000*socat_opts.pollintv.tv_sec +
socat_opts.pollintv.tv_usec/1000;
if (closing == 0 || ptimeout < timeout) {
timeout = ptimeout;
}
}
/* now the fds will be assigned */
if (XIO_READABLE(sock1) &&
!(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof) &&
!socat_opts.righttoleft) {
if (!mayrd1) {
if (!mayrd1 && !(XIO_RDSTREAM(sock1)->eof > 1)) {
fd1in->fd = XIO_GETRDFD(sock1);
fd1in->events = POLLIN;
} else {
@ -840,7 +846,7 @@ int _socat(void) {
if (XIO_READABLE(sock2) &&
!(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof) &&
!socat_opts.lefttoright) {
if (!mayrd2) {
if (!mayrd2 && !(XIO_RDSTREAM(sock2)->eof > 1)) {
fd2in->fd = XIO_GETRDFD(sock2);
fd2in->events = POLLIN;
} else {
@ -856,13 +862,15 @@ int _socat(void) {
fd1out->fd = -1;
fd2in->fd = -1;
}
/* frame 0: innermost part of the transfer loop: check FD status */
retval = xiopoll(fds, 4, timeout);
_errno = errno;
if (retval < 0 && errno == EINTR) {
Info1("poll(): %s", strerror(errno));
if (retval >= 0 || errno != EINTR) {
break;
}
_errno = errno;
Info1("poll(): %s", strerror(errno));
errno = _errno;
} while (retval < 0 && errno == EINTR);
} while (true);
/* attention:
when an exec'd process sends data and terminates, it is unpredictable
@ -881,7 +889,13 @@ int _socat(void) {
closing>=1?socat_opts.closwait.tv_usec:socat_opts.total_timeout.tv_usec);
if (polling && !wasaction) {
/* there was a ignoreeof poll timeout, use it */
;
polling = 0; /*%%%*/
if (XIO_RDSTREAM(sock1)->ignoreeof) {
mayrd1 = 0;
}
} else if (polling && wasaction) {
wasaction = 0;
} else if (socat_opts.total_timeout.tv_sec != 0 ||
socat_opts.total_timeout.tv_usec != 0) {
/* there was a total inactivity timeout */
@ -970,11 +984,15 @@ int _socat(void) {
/* NOW handle EOFs */
/*0 Debug4("bytes1=F_Zd, XIO_RDSTREAM(sock1)->eof=%d, XIO_RDSTREAM(sock1)->ignoreeof=%d, closing=%d",
bytes1, XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock1)->ignoreeof,
closing);*/
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); /*! */
polling = 1;
mayrd1 = true;
polling = 1; /* do not hook this eof fd to poll for pollintv*/
} else {
Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1));
xioshutdown(sock2, SHUT_WR);
@ -982,13 +1000,16 @@ int _socat(void) {
break;
}
}
} else if (polling && XIO_RDSTREAM(sock1)->ignoreeof) {
polling = 0;
}
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);
polling = 1;
mayrd2 = true;
polling = 1; /* do not hook this eof fd to poll for pollintv*/
} else {
Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2));
xioshutdown(sock1, SHUT_WR);
@ -996,6 +1017,8 @@ int _socat(void) {
break;
}
}
} else if (polling && XIO_RDSTREAM(sock2)->ignoreeof) {
polling = 0;
}
}

101
test.sh
View File

@ -3218,19 +3218,13 @@ printf "test $F_n $TEST... " $N
touch "$ti"
$CMD >"$tf" 2>"$te" &
bg=$!
sleep 1
usleep 500000
echo "$da" >>"$ti"
sleep 1
kill $bg 2>/dev/null
if ! echo "$da" |diff - "$tf" >"$tdiff"; then
if [ -s "$te" ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD"
cat "$te"
else
$PRINTF "$FAILED: diff:\n"
cat "$tdiff"
fi
$PRINTF "$FAILED: diff:\n"
cat "$tdiff"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
@ -3240,7 +3234,7 @@ fi
wait
esac
N=$((N+1))
#set +vx
set +vx
NAME=EXECIGNOREEOF
@ -8152,7 +8146,7 @@ sleep 1
l="$(childprocess $pid1)"
rcc=$?
kill $pid1 2>/dev/null; wait
if [ $rc2 -ne 0 -o $rcc -ne 0 ]; then
if [ $rc2 -ne 0 ]; then
$PRINTF "$NO_RESULT\n" # already handled in test UDP4STREAM
numCANT=$((numCANT+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
@ -8203,7 +8197,7 @@ sleep 1
l="$(childprocess $pid1)"
rcc=$?
kill $pid1 2>/dev/null; wait
if [ $rc2 -ne 0 -o $rcc -ne 0 ]; then
if [ $rc2 -ne 0 ]; then
$PRINTF "$NO_RESULT\n" # already handled in test UDP4DGRAM
numCANT=$((numCANT+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
@ -8415,6 +8409,44 @@ PORT=$((PORT+1))
N=$((N+1))
# during wait for next poll time option ignoreeof blocked the data transfer in
# the reverse direction
NAME=IGNOREEOFNOBLOCK
case "$TESTS" in
*%functions%*|*%socket%*|*%ignoreeof%*|*%$NAME%*)
TEST="$NAME: ignoreeof does not block other direction"
# have socat poll in ignoreeof mode. while it waits one second for next check,
# we send data in the reverse direction and then the total timeout fires.
# it the data has passed, the test succeeded.
tf="$td/test$N.stout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"
CMD0="$SOCAT $opts /dev/null,ignoreeof!!- -!!/dev/null"
printf "test $F_n $TEST... " $N
(usleep 333333; echo "$da") |$CMD0 >"$tf" 2>"${te}0"
rc0=$?
if [ $rc0 != 0 ]; then
$PRINTF "$FAILED\n"
echo "$CMD0 &"
echo "$CMD1"
cat "${te}0"
cat "${te}1"
numFAIL=$((numFAIL+1))
elif echo "$da" |diff - "$tf" >/dev/null; then
$PRINTF "$OK\n"
numOK=$((numOK+1))
else
$PRINTF "$FAILED\n"
echo "$CMD0 &"
echo "$CMD1"
cat "${te}0"
numFAIL=$((numFAIL+1))
fi
esac
N=$((N+1))
echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed"
if [ "$numFAIL" -gt 0 ]; then
@ -8437,32 +8469,37 @@ wait
exit
# template
NAME=!!!
# test template
# give a description of what is tested (a bugfix, a new feature...)
NAME=SHORT_UNIQUE_TESTNAME
case "$TESTS" in
*%functions%*|*%$NAME%*)
TEST="$NAME: !!!"
*%functions%*|*%bugs%*|*%socket%*|*%$NAME%*)
TEST="$NAME: give a one line description of test"
# describe how the test is performed, and what's the success criteria
tf="$td/test$N.stout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"
CMD0="$SOCAT $opts server-address PIPE"
CMD1="$SOCAT - client-address"
printf "test $F_n $TEST... " $N
!!!
$CMD0 >/dev/null 2>"${te}0" &
pid0=$!
wait<something>port $xy 1
echo "$da" |$CMD1 >"${tf}1" 2>"${te}1"
rc1=$?
kill $pid0 2>/dev/null; wait
if [ !!! ]; then
$PRINTF "$OK\n"
numOK=$((numOK+1))
else
$PRINTF "$FAILED\n"
cat "$te"
echo "$CMD0 &"
echo "$CMD1"
cat "${te}0"
cat "${te}1"
numFAIL=$((numFAIL+1))
fi
esac
N=$((N+1))
TEST="$NAME: transferring from one file to another with echo"
tf1="$td/file$N.input"
tf2="$td/file$N.output"
testecho "$N" "$TEST" "" "echo" "$opts"
# MANUAL TESTS
# ZOMBIES
# have httpd on PORT/tcp
# nice -20 $SOCAT -d tcp-l:24080,fork tcp:$LOCALHOST:PORT
# i=0; while [ $i -lt 100 ]; do $ECHO 'GET / HTTP/1.0\n' |$SOCAT -t -,ignoreeof tcp:$LOCALHOST:24080 >/dev/null& i=$((i+1)); done