dnl Checks for headers
dnl
AC_CHECK_HEADERS(string.h stdarg.h unistd.h sys/time.h utime.h sys/utime.h pwd.h)
-AC_CHECK_HEADERS(termios.h sys/ioctl.h sys/select.h sys/utsname.h signal.h)
+AC_CHECK_HEADERS(termios.h sys/ioctl.h sys/select.h sys/utsname.h)
+AC_CHECK_HEADERS(signal.h setjmp.h)
AC_HEADER_TIME
dnl
AC_FUNC_ALLOCA
AC_FUNC_MMAP
AC_CHECK_FUNCS(strdup strstr strcasecmp strncasecmp strpbrk memmove)
-AC_CHECK_FUNCS(gettimeofday mktime strptime)
-AC_CHECK_FUNCS(strerror snprintf vsnprintf select signal symlink access isatty)
+AC_CHECK_FUNCS(gettimeofday mktime strptime strerror snprintf vsnprintf)
+AC_CHECK_FUNCS(select sigblock sigsetjmp signal symlink access isatty)
AC_CHECK_FUNCS(uname gethostname usleep)
dnl
# 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 "host.h"
#include "connect.h"
address_list_release (al);
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)
+
+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
+ than TIMEOUT seconds, -1 is returned and errno is set to
+ ETIMEDOUT. */
+
+static int
+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);
+ signal (SIGALRM, abort_connect);
+ if (SETJMP (abort_connect_env) != 0)
+ {
+ /* 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;
+}
+#endif /* UNIX_CONNECT_TIMEOUT */
+\f
/* A kludge, but still better than passing the host name all the way
to connect_to_one. */
static const char *connection_host_name;
}
/* Connect the socket to the remote host. */
- if (connect (sock, &sa.sa, sockaddr_len ()) < 0)
+ if (connect_with_timeout (sock, &sa.sa, sockaddr_len (), opt.timeout) < 0)
{
close (sock);
sock = -1;