Option accept-timeout (listen-timeout)

This commit is contained in:
Gerhard Rieger 2020-12-31 14:56:04 +01:00
parent aa2b9c00b2
commit 13ac417410
8 changed files with 124 additions and 1 deletions

View file

@ -151,6 +151,10 @@ New features:
Tests: OPENSSL_SNI OPENSSL_NO_SNI Tests: OPENSSL_SNI OPENSSL_NO_SNI
Thanks to Travis Burtrum for providing the initial patch Thanks to Travis Burtrum for providing the initial patch
New option accept-timeout (listen-timeout)
Test: ACCEPTTIMEOUT
Proposed by Roland
####################### V 1.7.3.4: ####################### V 1.7.3.4:
Corrections: Corrections:

View file

@ -749,6 +749,7 @@ label(ADDRESS_SCTP_LISTEN)dit(bf(tt(SCTP-LISTEN:<port>)))
link(pf)(OPTION_PROTOCOL_FAMILY), link(pf)(OPTION_PROTOCOL_FAMILY),
link(max-children)(OPTION_MAX_CHILDREN), link(max-children)(OPTION_MAX_CHILDREN),
link(backlog)(OPTION_BACKLOG), link(backlog)(OPTION_BACKLOG),
link(accept-timeout)(OPTION_ACCEPT_TIMEOUT),
link(sctp-maxseg)(OPTION_SCTP_MAXSEG), link(sctp-maxseg)(OPTION_SCTP_MAXSEG),
link(sctp-nodelay)(OPTION_SCTP_NODELAY), link(sctp-nodelay)(OPTION_SCTP_NODELAY),
link(su)(OPTION_SUBSTUSER), link(su)(OPTION_SUBSTUSER),
@ -1015,6 +1016,7 @@ label(ADDRESS_TCP_LISTEN)dit(bf(tt(TCP-LISTEN:<port>)))
link(pf)(OPTION_PROTOCOL_FAMILY), link(pf)(OPTION_PROTOCOL_FAMILY),
link(max-children)(OPTION_MAX_CHILDREN), link(max-children)(OPTION_MAX_CHILDREN),
link(backlog)(OPTION_BACKLOG), link(backlog)(OPTION_BACKLOG),
link(accept-timeout)(OPTION_ACCEPT_TIMEOUT),
link(mss)(OPTION_MSS), link(mss)(OPTION_MSS),
link(su)(OPTION_SUBSTUSER), link(su)(OPTION_SUBSTUSER),
link(reuseaddr)(OPTION_REUSEADDR), link(reuseaddr)(OPTION_REUSEADDR),
@ -2375,6 +2377,9 @@ startdit()
label(OPTION_BACKLOG)dit(bf(tt(backlog=<count>))) label(OPTION_BACKLOG)dit(bf(tt(backlog=<count>)))
Sets the backlog value passed with the code(listen()) system call to <count> Sets the backlog value passed with the code(listen()) system call to <count>
[link(int)(TYPE_INT)]. Default is 5. [link(int)(TYPE_INT)]. Default is 5.
label(OPTION_ACCEPT_TIMEOUT)dit(bf(tt(accept-timeout=<seconds>)))
End waiting for a connection after <seconds> [link(timeval)(TYPE_TIMEVAL)]
with error status.
label(OPTION_MAX_CHILDREN)dit(bf(tt(max-children=<count>))) label(OPTION_MAX_CHILDREN)dit(bf(tt(max-children=<count>)))
Limits the number of concurrent child processes [link(int)(TYPE_INT)]. Limits the number of concurrent child processes [link(int)(TYPE_INT)].
Default is no limit. Default is no limit.

59
test.sh
View file

@ -6548,6 +6548,7 @@ esac
N=$((N+1)) N=$((N+1))
# Test the connect-timeout address option
NAME=CONNECTTIMEOUT NAME=CONNECTTIMEOUT
case "$TESTS" in case "$TESTS" in
*%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%timeout%*|*%$NAME%*) *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%timeout%*|*%$NAME%*)
@ -14406,6 +14407,64 @@ esac
N=$((N+1)) N=$((N+1))
# Test the accept-timeout (listen-timeout) address option
NAME=ACCEPTTIMEOUT
case "$TESTS" in
*%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%listen%*|*%timeout%*|*%$NAME%*)
TEST="$NAME: test the accept-timeout option"
if ! eval $NUMCOND; then :;
elif ! feat=$(testaddrs tcp); then
$PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! feat=$(testoptions accept-timeout); then
$PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
else
# Just start a process with accept-timeout 1s and check if it still runs 2s later
# but before this, we test if the process waits at all
te1="$td/test$N.stderr1"
tk1="$td/test$N.kill1"
te2="$td/test$N.stderr2"
tk2="$td/test$N.kill2"
$PRINTF "test $F_n $TEST... " $N
# First, try to make socat hang and see if it can be killed
CMD1="$TRACE $SOCAT $opts TCP-LISTEN:$PORT,reuseaddr PIPE"
$CMD1 >"$te1" 2>&1 </dev/null &
pid1=$!
sleep 1
if ! kill $pid1 2>"$tk1"; then
$PRINTF "${YELLOW}does not hang${NORMAL}\n"
echo $CMD1 >&2
cat "$te1" >&2
cat "$tk1" >&2
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
else
# Second, set accept-timeout and see if socat exits before kill
CMD2="$TRACE $SOCAT $opts TCP-LISTEN:$PORT,reuseaddr,accept-timeout=1 PIPE" >"$te1" &
$CMD2 >"$te1" 2>&1 </dev/null &
pid2=$!
sleep 1
if kill $pid2 2>"$tk2"; then
$PRINTF "$FAILED\n"
echo "$CMD2" >&2
cat "$te2" >&2
cat "$tk2" >&2
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
else
$PRINTF "$OK\n"
numOK=$((numOK+1))
fi
fi
wait
fi ;; # testaddrs, NUMCOND
esac
N=$((N+1))
################################################################################## ##################################################################################
#================================================================================= #=================================================================================
# here come tests that might affect your systems integrity. Put normal tests # here come tests that might affect your systems integrity. Put normal tests

View file

@ -24,6 +24,7 @@ const struct optdesc opt_max_children = { "max-children", NULL, OPT_MAX_CHI
#if (WITH_UDP || WITH_TCP) #if (WITH_UDP || WITH_TCP)
const struct optdesc opt_range = { "range", NULL, OPT_RANGE, GROUP_RANGE, PH_ACCEPT, TYPE_STRING, OFUNC_SPEC }; const struct optdesc opt_range = { "range", NULL, OPT_RANGE, GROUP_RANGE, PH_ACCEPT, TYPE_STRING, OFUNC_SPEC };
#endif #endif
const struct optdesc opt_accept_timeout = { "accept-timeout", "listen-timeout", OPT_ACCEPT_TIMEOUT, GROUP_LISTEN, PH_LISTEN, TYPE_TIMEVAL, OFUNC_OFFSET, XIO_OFFSETOF(para.socket.accept_timeout) };
/* /*
@ -148,6 +149,7 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
} }
applyopts(xfd->fd, opts, PH_PASTSOCKET); applyopts(xfd->fd, opts, PH_PASTSOCKET);
applyopts_offset(xfd, opts);
applyopts_cloexec(xfd->fd, opts); applyopts_cloexec(xfd->fd, opts);
applyopts(xfd->fd, opts, PH_PREBIND); applyopts(xfd->fd, opts, PH_PREBIND);
@ -207,6 +209,7 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
applyopts(xfd->fd, opts, PH_PRELISTEN); applyopts(xfd->fd, opts, PH_PRELISTEN);
retropt_int(opts, OPT_BACKLOG, &backlog); retropt_int(opts, OPT_BACKLOG, &backlog);
applyopts(xfd->fd, opts, PH_LISTEN);
if (Listen(xfd->fd, backlog) < 0) { if (Listen(xfd->fd, backlog) < 0) {
Error3("listen(%d, %d): %s", xfd->fd, backlog, strerror(errno)); Error3("listen(%d, %d): %s", xfd->fd, backlog, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
@ -229,6 +232,51 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
do { do {
/*? int level = E_ERROR;*/ /*? int level = E_ERROR;*/
Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname))); Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname)));
if (xfd->para.socket.accept_timeout.tv_sec > 0 ||
xfd->para.socket.accept_timeout.tv_usec > 0) {
fd_set rfd;
struct timeval tmo;
FD_ZERO(&rfd);
FD_SET(xfd->fd, &rfd);
tmo.tv_sec = xfd->para.socket.accept_timeout.tv_sec;
tmo.tv_usec = xfd->para.socket.accept_timeout.tv_usec;
while (1) {
if (Select(xfd->fd+1, &rfd, NULL, NULL, &tmo) < 0) {
if (errno != EINTR) {
Error5("Select(%d, &0x%lx, NULL, NULL, {%ld.%ld}): %s", xfd->fd+1, 1<<(xfd->fd+1),
xfd->para.socket.accept_timeout.tv_sec, xfd->para.socket.accept_timeout.tv_usec,
strerror(errno));
}
} else {
break;
}
}
if (!FD_ISSET(xfd->fd, &rfd)) {
struct sigaction act;
Warn1("accept: %s", strerror(ETIMEDOUT));
Close(xfd->fd);
Notice("Waiting for child processes to terminate");
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_NOCLDSTOP/*|SA_RESTART*/
#ifdef SA_SIGINFO /* not on Linux 2.0(.33) */
|SA_SIGINFO
#endif
#ifdef SA_NOMASK
|SA_NOMASK
#endif
;
#if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
act.sa_sigaction = 0;
#else /* Linux 2.0(.33) does not have sigaction.sa_sigaction */
act.sa_handler = 0;
#endif
sigemptyset(&act.sa_mask);
Sigaction(SIGCHLD, &act, NULL);
wait(NULL);
Exit(0);
}
}
ps = Accept(xfd->fd, (struct sockaddr *)&sa, &salen); ps = Accept(xfd->fd, (struct sockaddr *)&sa, &salen);
if (ps >= 0) { if (ps >= 0) {
/*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", xfd->fd, &sa, salen, ps);*/ /*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", xfd->fd, &sa, salen, ps);*/

View file

@ -9,6 +9,7 @@ extern const struct optdesc opt_backlog;
extern const struct optdesc opt_fork; extern const struct optdesc opt_fork;
extern const struct optdesc opt_max_children; extern const struct optdesc opt_max_children;
extern const struct optdesc opt_range; extern const struct optdesc opt_range;
extern const struct optdesc opt_accept_timeout;
int int
xioopen_listen(struct single *xfd, int xioflags, xioopen_listen(struct single *xfd, int xioflags,

3
xio.h
View file

@ -182,6 +182,9 @@ typedef struct single {
#if _WITH_SOCKET #if _WITH_SOCKET
struct { struct {
struct timeval connect_timeout; /* how long to hang in connect() */ struct timeval connect_timeout; /* how long to hang in connect() */
#if WITH_LISTEN
struct timeval accept_timeout; /* how long to wait for incoming connection */
#endif
union sockaddr_union la; /* local socket address */ union sockaddr_union la; /* local socket address */
bool null_eof; /* with dgram: empty packet means EOF */ bool null_eof; /* with dgram: empty packet means EOF */
bool dorange; bool dorange;

View file

@ -150,6 +150,7 @@ const struct optname optionnames[] = {
#ifdef TCP_ABORT_THRESHOLD /* HP_UX */ #ifdef TCP_ABORT_THRESHOLD /* HP_UX */
IF_TCP ("abort-threshold", &opt_tcp_abort_threshold) IF_TCP ("abort-threshold", &opt_tcp_abort_threshold)
#endif #endif
IF_SOCKET ("accept-timeout", &opt_accept_timeout)
#ifdef SO_ACCEPTCONN /* AIX433 */ #ifdef SO_ACCEPTCONN /* AIX433 */
IF_SOCKET ("acceptconn", &opt_so_acceptconn) IF_SOCKET ("acceptconn", &opt_so_acceptconn)
#endif /* SO_ACCEPTCONN */ #endif /* SO_ACCEPTCONN */
@ -875,6 +876,7 @@ const struct optname optionnames[] = {
IF_TCP ("linger2", &opt_tcp_linger2) IF_TCP ("linger2", &opt_tcp_linger2)
#endif #endif
IF_PTY ("link", &opt_symbolic_link) IF_PTY ("link", &opt_symbolic_link)
IF_SOCKET ("listen-timeout", &opt_accept_timeout)
IF_TERMIOS("lnext", &opt_vlnext) IF_TERMIOS("lnext", &opt_vlnext)
#if defined(F_SETLKW) #if defined(F_SETLKW)
IF_ANY ("lock", &opt_f_setlkw_wr) /* POSIX, first choice */ IF_ANY ("lock", &opt_f_setlkw_wr) /* POSIX, first choice */
@ -2216,7 +2218,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
} }
(*opts)[i].value.u_timeval.tv_sec = val; (*opts)[i].value.u_timeval.tv_sec = val;
(*opts)[i].value.u_timeval.tv_usec = (*opts)[i].value.u_timeval.tv_usec =
(val-(*opts)[i].value.u_timeval.tv_sec) * 1000000; (val-(*opts)[i].value.u_timeval.tv_sec+0.0000005) * 1000000;
} }
break; break;

View file

@ -436,6 +436,7 @@ enum e_optcode {
OPT_IXANY, /* termios.c_iflag */ OPT_IXANY, /* termios.c_iflag */
OPT_IXOFF, /* termios.c_iflag */ OPT_IXOFF, /* termios.c_iflag */
OPT_IXON, /* termios.c_iflag */ OPT_IXON, /* termios.c_iflag */
OPT_ACCEPT_TIMEOUT, /* listening socket */
OPT_LOCKFILE, OPT_LOCKFILE,
OPT_LOWPORT, OPT_LOWPORT,
OPT_MAX_CHILDREN, OPT_MAX_CHILDREN,