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 fix: replaced FOPEN_MAX with FD_SETSIZE
thanks to Daniel Lucq for reporting this problem. 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 corrected some print statements and variable names
make uninstall did not uninstall procan 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)) 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" echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed"
if [ "$numFAIL" -gt 0 ]; then if [ "$numFAIL" -gt 0 ]; then

View file

@ -1,5 +1,5 @@
/* source: xio-ipapp.c */ /* 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 */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for TCP and UDP related options */ /* 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; return STAT_NORETRY;
} }
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
if (xioopts.logopt == 'm') { if (xioopts.logopt == 'm') {
Info("starting connect loop, switching to syslog"); Info("starting connect loop, switching to syslog");
diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y'; diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y';

View file

@ -1,5 +1,5 @@
/* source: xio-listen.c */ /* 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 */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for listen socket options */ /* 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 (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
#if 1
if (dofork) { if (dofork) {
#if HAVE_SIGACTION xiosetchilddied(); /* set SIGCHLD handler */
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) { if ((xfd->fd = Socket(pf, socktype, proto)) < 0) {
Msg4(level, Msg4(level,

View file

@ -1,5 +1,5 @@
/* source: xio-openssl.c */ /* 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 */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the implementation of the openssl addresses */ /* this file contains the implementation of the openssl addresses */
@ -268,6 +268,10 @@ static int
default: return STAT_NORETRY; default: return STAT_NORETRY;
} }
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
#if WITH_RETRY #if WITH_RETRY
if (dofork) { if (dofork) {
pid_t pid; 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) /*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL)
return STAT_RETRYLATER;*/ return STAT_RETRYLATER;*/
retropt_bool(*copts, OPT_STDERR, &withstderr); 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) { if (withfork) {
const char *forkwaitstring; const char *forkwaitstring;

View file

@ -1,5 +1,5 @@
/* source: xio-proxy.c */ /* 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 */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of HTTP proxy CONNECT /* 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; return result;
} }
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
#if WITH_RETRY #if WITH_RETRY
if (dofork) { if (dofork) {
pid_t pid; pid_t pid;

View file

@ -1,5 +1,5 @@
/* source: xio-socket.c */ /* 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 */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for socket related functions */ /* 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; return result;
} }
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
#if WITH_RETRY #if WITH_RETRY
if (dofork) { if (dofork) {
pid_t pid; 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 (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) { if ((xfd->fd = Socket(pf, socktype, proto)) < 0) {
Msg4(level, Msg4(level,
"socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno));

View file

@ -1,5 +1,5 @@
/* source: xio-socks.c */ /* 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 */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of socks4 type */ /* 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; return result;
} }
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
#if WITH_RETRY #if WITH_RETRY
if (dofork) { if (dofork) {
pid_t pid; pid_t pid;

View file

@ -1,5 +1,5 @@
/* source: xio-udp.c */ /* 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 */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for handling UDP addresses */ /* 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); 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 */ while (true) { /* we loop with fork or prohibited packets */
/* now wait for some packet on this datagram socket, get its sender /* now wait for some packet on this datagram socket, get its sender
address, connect there, and return */ address, connect there, and return */

1
xio.h
View file

@ -388,6 +388,7 @@ extern pid_t diedunknown3;
extern pid_t diedunknown4; extern pid_t diedunknown4;
extern int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)); 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 int xio_opt_signal(pid_t pid, int signum);
extern void childdied(int signum); extern void childdied(int signum);

View file

@ -1,5 +1,5 @@
/* source: xiosigchld.c */ /* 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 */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this is the source of the extended child signal handler */ /* this is the source of the extended child signal handler */
@ -157,3 +157,26 @@ void childdied(int signum) {
Info("childdied() finished"); Info("childdied() finished");
errno = _errno; 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;
}