mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 23:42:34 +00:00
Option accept-timeout (listen-timeout)
This commit is contained in:
parent
aa2b9c00b2
commit
13ac417410
8 changed files with 124 additions and 1 deletions
4
CHANGES
4
CHANGES
|
@ -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:
|
||||||
|
|
|
@ -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
59
test.sh
|
@ -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
|
||||||
|
|
48
xio-listen.c
48
xio-listen.c
|
@ -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);*/
|
||||||
|
|
|
@ -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
3
xio.h
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue