fixed bugs where sub processes would become zombies because the master process did not catch SIGCHLD

This commit is contained in:
Gerhard Rieger 2008-02-01 23:15:14 +01:00
parent c44985fb8d
commit 1f5165b765
13 changed files with 116 additions and 55 deletions

View file

@ -16,6 +16,12 @@ corrections:
fix: replaced FOPEN_MAX with FD_SETSIZE
thanks to Daniel Lucq for reporting this problem.
fixed bugs where sub processes would become zombies because the master
process did not catch SIGCHLD. this affected addresses UDP-LISTEN,
UDP-CONNECT, TCP-CONNECT, OPENSSL, PROXY, UNIX-CONNECT, UNIX-CLIENT,
ABSTRACT-CONNECT, ABSTRACT-CLIENT, SOCKSA, SOCKS4A
(thanks to Fernanda G Weiden for reporting this problem)
corrected some print statements and variable names
make uninstall did not uninstall procan

View file

@ -1 +1 @@
"1.6.0.0+execpty+servres+fd_setsize"
"1.6.0.0+execpty+servres+fd_setsize+udp_sigchld1"

50
test.sh
View file

@ -7979,6 +7979,56 @@ esac
N=$((N+1))
# there was a bug with udp-listen and fork: terminating sub processes became
# zombies because the master process did not catch SIGCHLD
NAME=UDP4LISTEN_SIGCHLD
case "$TESTS" in
*%functions%*|*%ip4%*|*%ipapp%*|*%udp%*|*%$NAME%*)
TEST="$NAME: test if UDP4-LISTEN child becomes zombie"
# idea: run a udp-listen process with fork and -T. Connect once, so a sub
# process is forked off. Make some transfer and wait until the -T timeout is
# over. Now check for the child process: if it is zombie the test failed.
# Correct is that child process terminated
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
tsl=$PORT
ts="$LOCALHOST:$tsl"
da=$(date)
CMD1="$SOCAT $opts -T 0.5 UDP4-LISTEN:$tsl,reuseaddr,fork PIPE"
CMD2="$SOCAT $opts - UDP4:$ts"
printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" &
pid1=$!
waitudp4port $tsl 1
echo "$da" |$CMD2 >>"$tf" 2>>"${te}2"
rc2=$?
sleep 1
#read -p ">"
l="$(childprocess $pid1)"
kill $pid1 2>/dev/null; wait
if [ $rc2 -ne 0 ]; then
$PRINTF "$NO_RESULT\n" # already handled in test UDP4STREAM
numCANT=$((numCANT+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$NO_RESULT\n" # already handled in test UDP4STREAM
numCANT=$((numCANT+1))
elif $(isdefunct "$l"); then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD1 &"
echo "$CMD2"
cat "${te}1" "${te}2"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi
numOK=$((numOK+1))
fi ;;
esac
PORT=$((PORT+1))
N=$((N+1))
echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed"
if [ "$numFAIL" -gt 0 ]; then

View file

@ -1,5 +1,5 @@
/* source: xio-ipapp.c */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for TCP and UDP related options */
@ -57,6 +57,10 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
return STAT_NORETRY;
}
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
if (xioopts.logopt == 'm') {
Info("starting connect loop, switching to syslog");
diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y';

View file

@ -1,5 +1,5 @@
/* source: xio-listen.c */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for listen socket options */
@ -115,28 +115,9 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
#if 1
if (dofork) {
#if HAVE_SIGACTION
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_NOCLDSTOP|SA_RESTART
#ifdef SA_NOMASK
|SA_NOMASK
#endif
;
act.sa_handler = childdied;
if (Sigaction(SIGCHLD, &act, NULL) < 0) {
/*! man does not say that errno is defined */
Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied, strerror(errno));
}
#else /* HAVE_SIGACTION */
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
}
#endif /* !HAVE_SIGACTION */
xiosetchilddied(); /* set SIGCHLD handler */
}
#endif /* 1 */
if ((xfd->fd = Socket(pf, socktype, proto)) < 0) {
Msg4(level,

View file

@ -1,5 +1,5 @@
/* source: xio-openssl.c */
/* Copyright Gerhard Rieger 2002-2007 */
/* Copyright Gerhard Rieger 2002-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the implementation of the openssl addresses */
@ -268,6 +268,10 @@ static int
default: return STAT_NORETRY;
}
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
#if WITH_RETRY
if (dofork) {
pid_t pid;

View file

@ -399,9 +399,8 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
/*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL)
return STAT_RETRYLATER;*/
retropt_bool(*copts, OPT_STDERR, &withstderr);
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
}
xiosetchilddied(); /* set SIGCHLD handler */
if (withfork) {
const char *forkwaitstring;

View file

@ -1,5 +1,5 @@
/* source: xio-proxy.c */
/* Copyright Gerhard Rieger 2002-2006 */
/* Copyright Gerhard Rieger 2002-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of HTTP proxy CONNECT
@ -185,6 +185,10 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
return result;
}
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
#if WITH_RETRY
if (dofork) {
pid_t pid;

View file

@ -1,5 +1,5 @@
/* source: xio-socket.c */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for socket related functions */
@ -401,6 +401,10 @@ int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
return result;
}
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
#if WITH_RETRY
if (dofork) {
pid_t pid;
@ -554,29 +558,6 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
#if 1
if (dofork) {
#if HAVE_SIGACTION
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_NOCLDSTOP|SA_RESTART
#ifdef SA_NOMASK
|SA_NOMASK
#endif
;
act.sa_handler = childdied;
if (Sigaction(SIGCHLD, &act, NULL) < 0) {
/*! man does not say that errno is defined */
Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied, strerror(errno));
}
#else /* HAVE_SIGACTION */
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
}
#endif /* !HAVE_SIGACTION */
}
#endif /* 1 */
if ((xfd->fd = Socket(pf, socktype, proto)) < 0) {
Msg4(level,
"socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno));

View file

@ -1,5 +1,5 @@
/* source: xio-socks.c */
/* Copyright Gerhard Rieger 2001-2006 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of socks4 type */
@ -163,6 +163,10 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
return result;
}
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
#if WITH_RETRY
if (dofork) {
pid_t pid;

View file

@ -1,5 +1,5 @@
/* source: xio-udp.c */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for handling UDP addresses */
@ -164,6 +164,10 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
}
retropt_bool(opts, OPT_LOWPORT, &fd->stream.para.socket.ip.lowport);
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
while (true) { /* we loop with fork or prohibited packets */
/* now wait for some packet on this datagram socket, get its sender
address, connect there, and return */

1
xio.h
View file

@ -388,6 +388,7 @@ extern pid_t diedunknown3;
extern pid_t diedunknown4;
extern int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *));
extern int xiosetchilddied(void);
extern int xio_opt_signal(pid_t pid, int signum);
extern void childdied(int signum);

View file

@ -1,5 +1,5 @@
/* source: xiosigchld.c */
/* Copyright Gerhard Rieger 2001-2006 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this is the source of the extended child signal handler */
@ -157,3 +157,26 @@ void childdied(int signum) {
Info("childdied() finished");
errno = _errno;
}
int xiosetchilddied(void) {
#if HAVE_SIGACTION
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_NOCLDSTOP|SA_RESTART
#ifdef SA_NOMASK
|SA_NOMASK
#endif
;
act.sa_handler = childdied;
if (Sigaction(SIGCHLD, &act, NULL) < 0) {
/*! man does not say that errno is defined */
Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied, strerror(errno));
}
#else /* HAVE_SIGACTION */
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
}
#endif /* !HAVE_SIGACTION */
return 0;
}