1
0
mirror of https://github.com/moparisthebest/wget synced 2024-07-03 16:38:41 -04:00

[svn] Generalize connect_with_timeout into run_with_timeout.

Published in <sxs4rifxndi.fsf@florida.arsdigita.de>.
This commit is contained in:
hniksic 2002-04-13 15:18:28 -07:00
parent 5390ada318
commit f3d3a50a56
5 changed files with 128 additions and 79 deletions

View File

@ -1,3 +1,14 @@
2002-04-14 Hrvoje Niksic <hniksic@arsdigita.com>
* connect.c (connect_with_timeout): Firing SIGALRM can result in
connect() exiting with EINTR. Treat EINTR the same as ETIMEDOUT.
2002-04-13 Hrvoje Niksic <hniksic@arsdigita.com>
* connect.c (connect_with_timeout): Use it.
* utils.c (run_with_timeout): New function.
2002-04-13 Hrvoje Niksic <hniksic@arsdigita.com> 2002-04-13 Hrvoje Niksic <hniksic@arsdigita.com>
* url.c (getproxy): Accept a struct url argument. This obviates * url.c (getproxy): Accept a struct url argument. This obviates

View File

@ -47,29 +47,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
# include <sys/select.h> # include <sys/select.h>
#endif /* HAVE_SYS_SELECT_H */ #endif /* HAVE_SYS_SELECT_H */
/* To implement connect with timeout, we need signal and either
sigsetjmp or sigblock. */
#undef UNIX_CONNECT_TIMEOUT
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif
#ifdef HAVE_SETJMP_H
# include <setjmp.h>
#endif
/* If sigsetjmp is a macro, configure won't pick it up. */
#ifdef sigsetjmp
# define HAVE_SIGSETJMP
#endif
#ifdef HAVE_SIGNAL
# ifdef HAVE_SIGSETJMP
# define UNIX_CONNECT_TIMEOUT
# endif
# ifdef HAVE_SIGBLOCK
# define UNIX_CONNECT_TIMEOUT
# endif
#endif
#include "wget.h" #include "wget.h"
#include "utils.h"
#include "host.h" #include "host.h"
#include "connect.h" #include "connect.h"
@ -107,45 +86,19 @@ resolve_bind_address (void)
bind_address_resolved = 1; bind_address_resolved = 1;
} }
#ifndef UNIX_CONNECT_TIMEOUT struct cwt_context {
static int int fd;
connect_with_timeout (int fd, const struct sockaddr *addr, int addrlen, const struct sockaddr *addr;
int timeout) int addrlen;
int result;
};
static void
connect_with_timeout_callback (void *arg)
{ {
return connect (fd, addr, addrlen); struct cwt_context *ctx = (struct cwt_context *)arg;
ctx->result = connect (ctx->fd, ctx->addr, ctx->addrlen);
} }
#else /* UNIX_CONNECT_TIMEOUT */
/* Implementation of connect with timeout. */
#ifdef HAVE_SIGSETJMP
#define SETJMP(env) sigsetjmp (env, 1)
static sigjmp_buf abort_connect_env;
RETSIGTYPE
abort_connect (int ignored)
{
siglongjmp (abort_connect_env, -1);
}
#else /* not HAVE_SIGSETJMP */
#define SETJMP(env) setjmp (env)
static jmp_buf abort_connect_env;
RETSIGTYPE
abort_connect (int ignored)
{
/* We don't have siglongjmp to preserve the set of blocked signals;
if we longjumped out of the handler at this point, SIGALRM would
remain blocked. We must unblock it manually. */
int mask = siggetmask ();
mask &= ~sigmask(SIGALRM);
sigsetmask (mask);
/* Now it's safe to longjump. */
longjmp (abort_connect_env, -1);
}
#endif /* not HAVE_SIGSETJMP */
/* Like connect, but specifies a timeout. If connecting takes longer /* Like connect, but specifies a timeout. If connecting takes longer
than TIMEOUT seconds, -1 is returned and errno is set to than TIMEOUT seconds, -1 is returned and errno is set to
@ -155,32 +108,20 @@ static int
connect_with_timeout (int fd, const struct sockaddr *addr, int addrlen, connect_with_timeout (int fd, const struct sockaddr *addr, int addrlen,
int timeout) int timeout)
{ {
int result, saved_errno; struct cwt_context ctx;
ctx.fd = fd;
ctx.addr = addr;
ctx.addrlen = addrlen;
if (timeout == 0) if (run_with_timeout (timeout, connect_with_timeout_callback, &ctx))
return connect (fd, addr, addrlen);
signal (SIGALRM, abort_connect);
if (SETJMP (abort_connect_env) != 0)
{ {
/* Longjumped out of connect with a timeout. */
signal (SIGALRM, SIG_DFL);
errno = ETIMEDOUT; errno = ETIMEDOUT;
return -1; return -1;
} }
if (ctx.result == -1 && errno == EINTR)
alarm (timeout); errno = ETIMEDOUT;
result = connect (fd, addr, addrlen); return ctx.result;
saved_errno = errno; /* In case alarm() or signal() change
errno. */
alarm (0);
signal (SIGALRM, SIG_DFL);
errno = saved_errno;
return result;
} }
#endif /* UNIX_CONNECT_TIMEOUT */
/* A kludge, but still better than passing the host name all the way /* A kludge, but still better than passing the host name all the way
to connect_to_one. */ to connect_to_one. */

View File

@ -551,6 +551,10 @@ lookup_host (const char *host, int silent)
if (!silent) if (!silent)
logprintf (LOG_VERBOSE, _("Resolving %s... "), host); logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
/* Host name lookup goes on below. #### We should implement
getaddrinfo_with_timeout and gethostbyname_with_timeout the same
way connect.c implements connect_with_timeout. */
#ifdef INET6 #ifdef INET6
{ {
struct addrinfo hints, *ai; struct addrinfo hints, *ai;

View File

@ -59,6 +59,27 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
# include <termios.h> # include <termios.h>
#endif #endif
/* Needed for run_with_timeout. */
#undef USE_SIGNAL_TIMEOUT
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif
#ifdef HAVE_SETJMP_H
# include <setjmp.h>
#endif
/* If sigsetjmp is a macro, configure won't pick it up. */
#ifdef sigsetjmp
# define HAVE_SIGSETJMP
#endif
#ifdef HAVE_SIGNAL
# ifdef HAVE_SIGSETJMP
# define USE_SIGNAL_TIMEOUT
# endif
# ifdef HAVE_SIGBLOCK
# define USE_SIGNAL_TIMEOUT
# endif
#endif
#include "wget.h" #include "wget.h"
#include "utils.h" #include "utils.h"
#include "fnmatch.h" #include "fnmatch.h"
@ -1757,3 +1778,73 @@ debug_test_md5 (char *buf)
return res; return res;
} }
#endif #endif
/* Implementation of run_with_timeout, a generic timeout handler for
systems with Unix-like signal handling. */
#ifdef HAVE_SIGSETJMP
#define SETJMP(env) sigsetjmp (env, 1)
static sigjmp_buf run_with_timeout_env;
static RETSIGTYPE
abort_run_with_timeout (int sig)
{
assert (sig == SIGALRM);
siglongjmp (run_with_timeout_env, -1);
}
#else /* not HAVE_SIGSETJMP */
#define SETJMP(env) setjmp (env)
static jmp_buf run_with_timeout_env;
static RETSIGTYPE
abort_run_with_timeout (int sig)
{
assert (sig == SIGALRM);
/* We don't have siglongjmp to preserve the set of blocked signals;
if we longjumped out of the handler at this point, SIGALRM would
remain blocked. We must unblock it manually. */
int mask = siggetmask ();
mask &= ~sigmask(SIGALRM);
sigsetmask (mask);
/* Now it's safe to longjump. */
longjmp (run_with_timeout_env, -1);
}
#endif /* not HAVE_SIGSETJMP */
int
run_with_timeout (long timeout, void (*fun) (void *), void *arg)
{
#ifndef USE_SIGNAL_TIMEOUT
fun (arg);
return 0;
#else
int saved_errno;
if (timeout == 0)
{
fun (arg);
return 0;
}
signal (SIGALRM, abort_run_with_timeout);
if (SETJMP (run_with_timeout_env) != 0)
{
/* Longjumped out of FUN with a timeout. */
signal (SIGALRM, SIG_DFL);
return 1;
}
alarm (timeout);
fun (arg);
/* Preserve errno in case alarm() or signal() modifies it. */
saved_errno = errno;
alarm (0);
signal (SIGALRM, SIG_DFL);
errno = saved_errno;
return 0;
#endif
}

View File

@ -106,4 +106,6 @@ char *html_quote_string PARAMS ((const char *));
int determine_screen_width PARAMS ((void)); int determine_screen_width PARAMS ((void));
int random_number PARAMS ((int)); int random_number PARAMS ((int));
int run_with_timeout PARAMS ((long, void (*) (void *), void *));
#endif /* UTILS_H */ #endif /* UTILS_H */