mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +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
|
||||
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:
|
||||
|
||||
Corrections:
|
||||
|
|
|
@ -749,6 +749,7 @@ label(ADDRESS_SCTP_LISTEN)dit(bf(tt(SCTP-LISTEN:<port>)))
|
|||
link(pf)(OPTION_PROTOCOL_FAMILY),
|
||||
link(max-children)(OPTION_MAX_CHILDREN),
|
||||
link(backlog)(OPTION_BACKLOG),
|
||||
link(accept-timeout)(OPTION_ACCEPT_TIMEOUT),
|
||||
link(sctp-maxseg)(OPTION_SCTP_MAXSEG),
|
||||
link(sctp-nodelay)(OPTION_SCTP_NODELAY),
|
||||
link(su)(OPTION_SUBSTUSER),
|
||||
|
@ -1015,6 +1016,7 @@ label(ADDRESS_TCP_LISTEN)dit(bf(tt(TCP-LISTEN:<port>)))
|
|||
link(pf)(OPTION_PROTOCOL_FAMILY),
|
||||
link(max-children)(OPTION_MAX_CHILDREN),
|
||||
link(backlog)(OPTION_BACKLOG),
|
||||
link(accept-timeout)(OPTION_ACCEPT_TIMEOUT),
|
||||
link(mss)(OPTION_MSS),
|
||||
link(su)(OPTION_SUBSTUSER),
|
||||
link(reuseaddr)(OPTION_REUSEADDR),
|
||||
|
@ -2375,6 +2377,9 @@ startdit()
|
|||
label(OPTION_BACKLOG)dit(bf(tt(backlog=<count>)))
|
||||
Sets the backlog value passed with the code(listen()) system call to <count>
|
||||
[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>)))
|
||||
Limits the number of concurrent child processes [link(int)(TYPE_INT)].
|
||||
Default is no limit.
|
||||
|
|
59
test.sh
59
test.sh
|
@ -6548,6 +6548,7 @@ esac
|
|||
N=$((N+1))
|
||||
|
||||
|
||||
# Test the connect-timeout address option
|
||||
NAME=CONNECTTIMEOUT
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%timeout%*|*%$NAME%*)
|
||||
|
@ -14406,6 +14407,64 @@ esac
|
|||
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
|
||||
|
|
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)
|
||||
const struct optdesc opt_range = { "range", NULL, OPT_RANGE, GROUP_RANGE, PH_ACCEPT, TYPE_STRING, OFUNC_SPEC };
|
||||
#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_offset(xfd, opts);
|
||||
applyopts_cloexec(xfd->fd, opts);
|
||||
|
||||
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);
|
||||
retropt_int(opts, OPT_BACKLOG, &backlog);
|
||||
applyopts(xfd->fd, opts, PH_LISTEN);
|
||||
if (Listen(xfd->fd, backlog) < 0) {
|
||||
Error3("listen(%d, %d): %s", xfd->fd, backlog, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
|
@ -229,6 +232,51 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
|
|||
do {
|
||||
/*? int level = E_ERROR;*/
|
||||
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);
|
||||
if (ps >= 0) {
|
||||
/*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_max_children;
|
||||
extern const struct optdesc opt_range;
|
||||
extern const struct optdesc opt_accept_timeout;
|
||||
|
||||
int
|
||||
xioopen_listen(struct single *xfd, int xioflags,
|
||||
|
|
3
xio.h
3
xio.h
|
@ -182,6 +182,9 @@ typedef struct single {
|
|||
#if _WITH_SOCKET
|
||||
struct {
|
||||
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 */
|
||||
bool null_eof; /* with dgram: empty packet means EOF */
|
||||
bool dorange;
|
||||
|
|
|
@ -150,6 +150,7 @@ const struct optname optionnames[] = {
|
|||
#ifdef TCP_ABORT_THRESHOLD /* HP_UX */
|
||||
IF_TCP ("abort-threshold", &opt_tcp_abort_threshold)
|
||||
#endif
|
||||
IF_SOCKET ("accept-timeout", &opt_accept_timeout)
|
||||
#ifdef SO_ACCEPTCONN /* AIX433 */
|
||||
IF_SOCKET ("acceptconn", &opt_so_acceptconn)
|
||||
#endif /* SO_ACCEPTCONN */
|
||||
|
@ -875,6 +876,7 @@ const struct optname optionnames[] = {
|
|||
IF_TCP ("linger2", &opt_tcp_linger2)
|
||||
#endif
|
||||
IF_PTY ("link", &opt_symbolic_link)
|
||||
IF_SOCKET ("listen-timeout", &opt_accept_timeout)
|
||||
IF_TERMIOS("lnext", &opt_vlnext)
|
||||
#if defined(F_SETLKW)
|
||||
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_usec =
|
||||
(val-(*opts)[i].value.u_timeval.tv_sec) * 1000000;
|
||||
(val-(*opts)[i].value.u_timeval.tv_sec+0.0000005) * 1000000;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -436,6 +436,7 @@ enum e_optcode {
|
|||
OPT_IXANY, /* termios.c_iflag */
|
||||
OPT_IXOFF, /* termios.c_iflag */
|
||||
OPT_IXON, /* termios.c_iflag */
|
||||
OPT_ACCEPT_TIMEOUT, /* listening socket */
|
||||
OPT_LOCKFILE,
|
||||
OPT_LOWPORT,
|
||||
OPT_MAX_CHILDREN,
|
||||
|
|
Loading…
Reference in a new issue