diff --git a/CHANGES b/CHANGES index cd27fab..aa5a538 100644 --- a/CHANGES +++ b/CHANGES @@ -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 diff --git a/VERSION b/VERSION index e8ab444..7420a71 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -"1.6.0.0+execpty+servres+fd_setsize" +"1.6.0.0+execpty+servres+fd_setsize+udp_sigchld1" diff --git a/test.sh b/test.sh index 3ccb45b..57f7074 100755 --- a/test.sh +++ b/test.sh @@ -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 diff --git a/xio-ipapp.c b/xio-ipapp.c index 835d701..1a3effd 100644 --- a/xio-ipapp.c +++ b/xio-ipapp.c @@ -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'; diff --git a/xio-listen.c b/xio-listen.c index 2f19b74..38a65c6 100644 --- a/xio-listen.c +++ b/xio-listen.c @@ -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, diff --git a/xio-openssl.c b/xio-openssl.c index 49ad5df..4fa17bc 100644 --- a/xio-openssl.c +++ b/xio-openssl.c @@ -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; diff --git a/xio-progcall.c b/xio-progcall.c index 372afad..1b9489f 100644 --- a/xio-progcall.c +++ b/xio-progcall.c @@ -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; diff --git a/xio-proxy.c b/xio-proxy.c index 5900e92..23ab032 100644 --- a/xio-proxy.c +++ b/xio-proxy.c @@ -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; diff --git a/xio-socket.c b/xio-socket.c index ac11fe4..c0c7037 100644 --- a/xio-socket.c +++ b/xio-socket.c @@ -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)); diff --git a/xio-socks.c b/xio-socks.c index d8a03df..71c0ded 100644 --- a/xio-socks.c +++ b/xio-socks.c @@ -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; diff --git a/xio-udp.c b/xio-udp.c index feacbc5..3907f98 100644 --- a/xio-udp.c +++ b/xio-udp.c @@ -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 */ diff --git a/xio.h b/xio.h index 3e15f5b..56af437 100644 --- a/xio.h +++ b/xio.h @@ -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); diff --git a/xiosigchld.c b/xiosigchld.c index e08853f..510463c 100644 --- a/xiosigchld.c +++ b/xiosigchld.c @@ -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; +}