mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 23:42:34 +00:00
UDP-LISTEN did not honor the max-children option
This commit is contained in:
parent
522cf716f8
commit
8e09093afd
3 changed files with 130 additions and 14 deletions
4
CHANGES
4
CHANGES
|
@ -35,6 +35,10 @@ corrections:
|
||||||
Test: USE_IPV6_JOIN_GROUP
|
Test: USE_IPV6_JOIN_GROUP
|
||||||
Thanks to Linux Lüssing for sending a patch.
|
Thanks to Linux Lüssing for sending a patch.
|
||||||
|
|
||||||
|
UDP-LISTEN did not honor the max-children option.
|
||||||
|
Test: UDP4MAXCHILDREN UDP6MAXCHILDREN
|
||||||
|
Thanks to Leander Berwers for reporting this issue.
|
||||||
|
|
||||||
porting:
|
porting:
|
||||||
Type conflict between int and sig_atomic_t between declaration and
|
Type conflict between int and sig_atomic_t between declaration and
|
||||||
definition of diag_immediate_type and diag_immediate_exit broke
|
definition of diag_immediate_type and diag_immediate_exit broke
|
||||||
|
|
122
test.sh
122
test.sh
|
@ -9884,7 +9884,7 @@ elif [ "$KEYW" = "TCP6" -o "$KEYW" = "UDP6" -o "$KEYW" = "SCTP6" ] && \
|
||||||
numCANT=$((numCANT+1))
|
numCANT=$((numCANT+1))
|
||||||
elif [ "$KEYW" = "SCTP4" ] && ! runssctp4 "$((PORT))"; then
|
elif [ "$KEYW" = "SCTP4" ] && ! runssctp4 "$((PORT))"; then
|
||||||
$PRINTF "test $F_n $TEST... ${YELLOW}$KEYW not available${NORMAL}\n" $N
|
$PRINTF "test $F_n $TEST... ${YELLOW}$KEYW not available${NORMAL}\n" $N
|
||||||
elif [ "$KEYW" = "SCTP6" ] && ! runssctp4 "$((PORT))"; then
|
elif [ "$KEYW" = "SCTP6" ] && ! runssctp6 "$((PORT))"; then
|
||||||
#!!! branch not reached - caught above!
|
#!!! branch not reached - caught above!
|
||||||
$PRINTF "test $F_n $TEST... ${YELLOW}$KEYW not available${NORMAL}\n" $N
|
$PRINTF "test $F_n $TEST... ${YELLOW}$KEYW not available${NORMAL}\n" $N
|
||||||
else
|
else
|
||||||
|
@ -11228,41 +11228,55 @@ PORT=$((PORT+1))
|
||||||
N=$((N+1))
|
N=$((N+1))
|
||||||
|
|
||||||
|
|
||||||
# test the max-children option
|
while read KEYW FEAT ADDR IPPORT; do
|
||||||
NAME=MAXCHILDREN
|
if [ -z "$KEYW" ]|| [[ "$KEYW" == \#* ]]; then continue; fi
|
||||||
|
PROTO=$KEYW
|
||||||
|
proto="$(echo "$PROTO" |tr A-Z a-z)"
|
||||||
|
# test the max-children option on really connection oriented sockets
|
||||||
|
NAME=${KEYW}MAXCHILDREN
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
*%$N%*|*%functions%*|*%socket%*|*%$NAME%*)
|
*%$N%*|*%functions%*|*%maxchildren%*|*%socket%*|*%$NAME%*)
|
||||||
TEST="$NAME: max-children option"
|
TEST="$NAME: max-children option"
|
||||||
# start a listen process with max-children=1; connect with a client, let it
|
# start a listen process with max-children=1; connect with a client, let it
|
||||||
# sleep some time before sending data; connect with second client that sends
|
# sleep some time before sending data; connect with second client that sends
|
||||||
# data immediately. If max-children is working correctly the first data should
|
# data immediately. If max-children is working correctly the first data should
|
||||||
# arrive first because the second process has to wait.
|
# arrive first because the second process has to wait.
|
||||||
if ! eval $NUMCOND; then :; else
|
if ! eval $NUMCOND; then :; else
|
||||||
ts="$td/test$N.sock"
|
case "X$IPPORT" in
|
||||||
|
"XPORT")
|
||||||
|
tsl=$PORT # test socket listen address
|
||||||
|
tsc="$ADDR:$PORT" # test socket connect address
|
||||||
|
PORT=$((PORT+1)) ;;
|
||||||
|
*)
|
||||||
|
tsl="$(eval echo "$ADDR")" # resolve $N
|
||||||
|
tsc=$tsl
|
||||||
|
esac
|
||||||
|
#ts="$td/test$N.sock"
|
||||||
tf="$td/test$N.stdout"
|
tf="$td/test$N.stdout"
|
||||||
te="$td/test$N.stderr"
|
te="$td/test$N.stderr"
|
||||||
tdiff="$td/test$N.diff"
|
tdiff="$td/test$N.diff"
|
||||||
da="test$N $(date) $RANDOM"
|
da="test$N $(date) $RANDOM"
|
||||||
CMD0="$TRACE $SOCAT $opts -U FILE:$tf,o-trunc,o-creat,o-append UNIX-L:$ts,fork,max-children=1"
|
CMD0="$TRACE $SOCAT $opts -U FILE:$tf,o-trunc,o-creat,o-append $PROTO-LISTEN:$tsl,fork,max-children=1"
|
||||||
CMD1="$TRACE $SOCAT $opts -u - UNIX-CONNECT:$ts"
|
CMD1="$TRACE $SOCAT $opts -u - $PROTO-CONNECT:$tsc"
|
||||||
printf "test $F_n $TEST... " $N
|
printf "test $F_n $TEST... " $N
|
||||||
$CMD0 >/dev/null 2>"${te}0" &
|
$CMD0 >/dev/null 2>"${te}0" &
|
||||||
pid0=$!
|
pid0=$!
|
||||||
waitunixport $ts 1
|
wait${proto}port $tsl 1
|
||||||
(sleep 2; echo "$da 1") |$CMD1 >"${tf}1" 2>"${te}1" &
|
(echo "$da 1"; sleep 2) |$CMD1 >"${tf}1" 2>"${te}1" &
|
||||||
pid1=$!
|
pid1=$!
|
||||||
sleep 1
|
sleep 1
|
||||||
echo "$da 2" |$CMD1 >"${tf}2" 2>"${te}2"
|
echo "$da 2" |$CMD1 >"${tf}2" 2>"${te}2" &
|
||||||
rc2=$?
|
pid2=$!
|
||||||
|
rc2=$!
|
||||||
sleep 2
|
sleep 2
|
||||||
kill $pid0 $pid1 2>/dev/null; wait
|
kill $pid1 $pid2 $pid0 2>/dev/null; wait
|
||||||
if echo -e "$da 1\n$da 2" |diff $tf - >$tdiff; then
|
if echo -e "$da 1\n$da 2" |diff - $tf >$tdiff; then
|
||||||
$PRINTF "$OK\n"
|
$PRINTF "$OK\n"
|
||||||
numOK=$((numOK+1))
|
numOK=$((numOK+1))
|
||||||
else
|
else
|
||||||
$PRINTF "$FAILED\n"
|
$PRINTF "$FAILED\n"
|
||||||
echo "$CMD0 &"
|
echo "$CMD0 &"
|
||||||
echo "(sleep 2; echo \"$da 1\") |$CMD1"
|
echo "(echo \"$da 1\"; sleep 2) |$CMD1"
|
||||||
echo "echo \"$da 2\" |$CMD1"
|
echo "echo \"$da 2\" |$CMD1"
|
||||||
cat "${te}0"
|
cat "${te}0"
|
||||||
cat "${te}1"
|
cat "${te}1"
|
||||||
|
@ -11275,6 +11289,86 @@ fi # NUMCOND
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
N=$((N+1))
|
N=$((N+1))
|
||||||
|
done <<<"
|
||||||
|
TCP4 TCP 127.0.0.1 PORT
|
||||||
|
TCP6 TCP 127.0.0.1 PORT
|
||||||
|
SCTP4 TCP 127.0.0.1 PORT
|
||||||
|
SCTP6 TCP 127.0.0.1 PORT
|
||||||
|
UNIX UNIX $td/test\$N.server -
|
||||||
|
"
|
||||||
|
# debugging this hanging test was difficult - following lessons learned:
|
||||||
|
# kill <parent> had no effect when child process existed
|
||||||
|
# strace -f (on Fedora-23) sometimes writes/pads? blocks with \0, overwriting client traces
|
||||||
|
# using the TRACE feature lets above kill command kill strace, not socat
|
||||||
|
# care for timing, understand what you want :-)
|
||||||
|
|
||||||
|
|
||||||
|
while read KEYW FEAT ADDR IPPORT; do
|
||||||
|
if [ -z "$KEYW" ]|| [[ "$KEYW" == \#* ]]; then continue; fi
|
||||||
|
PROTO=$KEYW
|
||||||
|
proto="$(echo "$PROTO" |tr A-Z a-z)"
|
||||||
|
# test the max-children option on pseudo connected sockets
|
||||||
|
NAME=${KEYW}MAXCHILDREN
|
||||||
|
case "$TESTS" in
|
||||||
|
*%$N%*|*%functions%*|*%maxchildren%*|*%socket%*|*%dgram%*|*%udp%*|*%$NAME%*)
|
||||||
|
TEST="$NAME: max-children option"
|
||||||
|
# start a listen process with max-children=1; connect with a client, let it
|
||||||
|
# send data and then sleep; connect with second client that wants to send
|
||||||
|
# data immediately, but keep first client active until server terminates.
|
||||||
|
#If max-children is working correctly only the first data should
|
||||||
|
# arrive.
|
||||||
|
if ! eval $NUMCOND; then :; else
|
||||||
|
case "X$IPPORT" in
|
||||||
|
"XPORT")
|
||||||
|
tsl=$PORT # test socket listen address
|
||||||
|
tsc="$ADDR:$PORT" # test socket connect address
|
||||||
|
PORT=$((PORT+1)) ;;
|
||||||
|
*)
|
||||||
|
tsl="$(eval echo "$ADDR")" # resolve $N
|
||||||
|
tsc=$tsl
|
||||||
|
esac
|
||||||
|
#ts="$td/test$N.sock"
|
||||||
|
tf="$td/test$N.stdout"
|
||||||
|
te="$td/test$N.stderr"
|
||||||
|
tdiff="$td/test$N.diff"
|
||||||
|
da="test$N $(date) $RANDOM"
|
||||||
|
CMD0="$TRACE $SOCAT $opts -U FILE:$tf,o-trunc,o-creat,o-append $PROTO-LISTEN:$tsl,fork,max-children=1"
|
||||||
|
CMD1="$TRACE $SOCAT $opts -u - $PROTO-CONNECT:$tsc"
|
||||||
|
printf "test $F_n $TEST... " $N
|
||||||
|
$CMD0 >/dev/null 2>"${te}0" &
|
||||||
|
pid0=$!
|
||||||
|
wait${proto}port $tsl 1
|
||||||
|
(echo "$da 1"; sleep 3) |$CMD1 >"${tf}1" 2>"${te}1" &
|
||||||
|
pid1=$!
|
||||||
|
sleep 1
|
||||||
|
echo "$da 2" |$CMD1 >"${tf}2" 2>"${te}2" &
|
||||||
|
pid2=$!
|
||||||
|
rc2=$!
|
||||||
|
sleep 1
|
||||||
|
kill -QUIT $pid1 $pid2 $pid0 2>/dev/null; wait
|
||||||
|
if echo -e "$da 1" |diff - $tf >$tdiff; then
|
||||||
|
$PRINTF "$OK\n"
|
||||||
|
numOK=$((numOK+1))
|
||||||
|
else
|
||||||
|
$PRINTF "$FAILED\n"
|
||||||
|
echo "$CMD0 &"
|
||||||
|
echo "(echo \"$da 1\"; sleep 2) |$CMD1"
|
||||||
|
echo "echo \"$da 2\" |$CMD1"
|
||||||
|
cat "${te}0"
|
||||||
|
cat "${te}1"
|
||||||
|
cat "${te}2"
|
||||||
|
cat "$tdiff"
|
||||||
|
numFAIL=$((numFAIL+1))
|
||||||
|
listFAIL="$listFAIL $N"
|
||||||
|
fi
|
||||||
|
fi # NUMCOND
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
N=$((N+1))
|
||||||
|
done <<<"
|
||||||
|
UDP4 UDP 127.0.0.1 PORT
|
||||||
|
UDP6 UDP 127.0.0.1 PORT
|
||||||
|
"
|
||||||
|
|
||||||
|
|
||||||
# socat up to 1.7.2.0 had a bug in xioscan_readline() that could be exploited
|
# socat up to 1.7.2.0 had a bug in xioscan_readline() that could be exploited
|
||||||
|
|
18
xio-udp.c
18
xio-udp.c
|
@ -86,6 +86,7 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
||||||
int socktype = SOCK_DGRAM;
|
int socktype = SOCK_DGRAM;
|
||||||
struct pollfd readfd;
|
struct pollfd readfd;
|
||||||
bool dofork = false;
|
bool dofork = false;
|
||||||
|
int maxchildren = 0;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
char *rangename;
|
char *rangename;
|
||||||
char infobuff[256];
|
char infobuff[256];
|
||||||
|
@ -142,6 +143,13 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retropt_int(opts, OPT_MAX_CHILDREN, &maxchildren);
|
||||||
|
|
||||||
|
if (! dofork && maxchildren) {
|
||||||
|
Error("option max-children not allowed without option fork");
|
||||||
|
return STAT_NORETRY;
|
||||||
|
}
|
||||||
|
|
||||||
#if WITH_IP4 /*|| WITH_IP6*/
|
#if WITH_IP4 /*|| WITH_IP6*/
|
||||||
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
|
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
|
||||||
if (xioparserange(rangename, pf, &fd->stream.para.socket.range) < 0) {
|
if (xioparserange(rangename, pf, &fd->stream.para.socket.range) < 0) {
|
||||||
|
@ -248,6 +256,8 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid == 0) { /* child */
|
if (pid == 0) { /* child */
|
||||||
|
pid_t cpid = Getpid();
|
||||||
|
xiosetenvulong("PID", cpid, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,6 +268,14 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
||||||
Info2("close(%d): %s", fd->stream.fd, strerror(errno));
|
Info2("close(%d): %s", fd->stream.fd, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (maxchildren) {
|
||||||
|
if (num_child < maxchildren) break;
|
||||||
|
Notice("maxchildren are active, waiting");
|
||||||
|
/* UINT_MAX would even be nicer, but Openindiana works only
|
||||||
|
with 31 bits */
|
||||||
|
while (!Sleep(INT_MAX)) ; /* any signal lets us continue */
|
||||||
|
}
|
||||||
|
Info("still listening");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue