# include <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 "utils.h"
#include "host.h"
#include "connect.h"
bind_address_resolved = 1;
}
\f
-#ifndef UNIX_CONNECT_TIMEOUT
-static int
-connect_with_timeout (int fd, const struct sockaddr *addr, int addrlen,
- int timeout)
-{
- return connect (fd, addr, addrlen);
-}
-#else /* UNIX_CONNECT_TIMEOUT */
-/* Implementation of connect with timeout. */
-
-#ifdef HAVE_SIGSETJMP
-#define SETJMP(env) sigsetjmp (env, 1)
+struct cwt_context {
+ int fd;
+ const struct sockaddr *addr;
+ int addrlen;
+ int result;
+};
-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)
+static void
+connect_with_timeout_callback (void *arg)
{
- /* 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);
+ struct cwt_context *ctx = (struct cwt_context *)arg;
+ ctx->result = connect (ctx->fd, ctx->addr, ctx->addrlen);
}
-#endif /* not HAVE_SIGSETJMP */
/* Like connect, but specifies a timeout. If connecting takes longer
than TIMEOUT seconds, -1 is returned and errno is set to
connect_with_timeout (int fd, const struct sockaddr *addr, int addrlen,
int timeout)
{
- int result, saved_errno;
-
- if (timeout == 0)
- return connect (fd, addr, addrlen);
+ struct cwt_context ctx;
+ ctx.fd = fd;
+ ctx.addr = addr;
+ ctx.addrlen = addrlen;
- signal (SIGALRM, abort_connect);
- if (SETJMP (abort_connect_env) != 0)
+ if (run_with_timeout (timeout, connect_with_timeout_callback, &ctx))
{
- /* Longjumped out of connect with a timeout. */
- signal (SIGALRM, SIG_DFL);
errno = ETIMEDOUT;
return -1;
}
-
- alarm (timeout);
- result = connect (fd, addr, addrlen);
-
- saved_errno = errno; /* In case alarm() or signal() change
- errno. */
- alarm (0);
- signal (SIGALRM, SIG_DFL);
- errno = saved_errno;
-
- return result;
+ if (ctx.result == -1 && errno == EINTR)
+ errno = ETIMEDOUT;
+ return ctx.result;
}
-#endif /* UNIX_CONNECT_TIMEOUT */
\f
/* A kludge, but still better than passing the host name all the way
to connect_to_one. */
# include <termios.h>
#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 "utils.h"
#include "fnmatch.h"
return res;
}
#endif
+\f
+/* 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
+}
+