You should have received a copy of the GNU General Public License
along with Wget; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+In addition, as a special exception, the Free Software Foundation
+gives permission to link the code of its release of Wget with the
+OpenSSL project's "OpenSSL" library (or with modified versions of it
+that use the same license as the "OpenSSL" library), and distribute
+the linked executables. You must obey the GNU General Public License
+in all respects for all of the code used other than "OpenSSL". If you
+modify this file, you may extend this exception to your version of the
+file, but you are not obligated to do so. If you do not wish to do
+so, delete this exception statement from your version. */
#include <config.h>
#include <stdio.h>
+#include <stdlib.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
# 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;
+ struct cwt_context ctx;
+ ctx.fd = fd;
+ ctx.addr = addr;
+ ctx.addrlen = addrlen;
- if (timeout == 0)
- return connect (fd, addr, 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. */
}
#ifdef HAVE_SELECT
-/* Wait for file descriptor FD to be readable, MAXTIME being the
- timeout in seconds. If WRITEP is non-zero, checks for FD being
- writable instead.
+/* Wait for file descriptor FD to be available, timing out after
+ MAXTIME seconds. "Available" means readable if writep is 0,
+ writeable otherwise.
+
+ Returns 1 if FD is available, 0 for timeout and -1 for error. */
- Returns 1 if FD is accessible, 0 for timeout and -1 for error in
- select(). */
int
select_fd (int fd, int maxtime, int writep)
{
- fd_set fds, exceptfds;
- struct timeval timeout;
+ fd_set fds;
+ fd_set *rd = NULL, *wrt = NULL;
+ struct timeval tmout;
+ int result;
FD_ZERO (&fds);
FD_SET (fd, &fds);
- FD_ZERO (&exceptfds);
- FD_SET (fd, &exceptfds);
- timeout.tv_sec = maxtime;
- timeout.tv_usec = 0;
- /* HPUX reportedly warns here. What is the correct incantation? */
- return select (fd + 1, writep ? NULL : &fds, writep ? &fds : NULL,
- &exceptfds, &timeout);
+ *(writep ? &wrt : &rd) = &fds;
+
+ tmout.tv_sec = maxtime;
+ tmout.tv_usec = 0;
+
+ do
+ result = select (fd + 1, rd, wrt, NULL, &tmout);
+ while (result < 0 && errno == EINTR);
+
+ /* When we've timed out, set errno to ETIMEDOUT for the convenience
+ of the caller. */
+ if (result == 0)
+ errno = ETIMEDOUT;
+
+ return result;
}
#endif /* HAVE_SELECT */
switch (mysrv.sa.sa_family)
{
-#ifdef INET6
+#ifdef ENABLE_IPV6
case AF_INET6:
memcpy (ip, &mysrv.sin6.sin6_addr, 16);
return 1;
and uses select() to timeout the stale connections (a connection is
stale if more than OPT.TIMEOUT time is spent in select() or
read()). */
+
int
iread (int fd, char *buf, int len)
{
int res;
- do
- {
#ifdef HAVE_SELECT
- if (opt.timeout)
- {
- do
- {
- res = select_fd (fd, opt.timeout, 0);
- }
- while (res == -1 && errno == EINTR);
- if (res <= 0)
- {
- /* Set errno to ETIMEDOUT on timeout. */
- if (res == 0)
- /* #### Potentially evil! */
- errno = ETIMEDOUT;
- return -1;
- }
- }
+ if (opt.timeout)
+ if (select_fd (fd, opt.timeout, 0) <= 0)
+ return -1;
#endif
- res = READ (fd, buf, len);
- }
+ do
+ res = READ (fd, buf, len);
while (res == -1 && errno == EINTR);
return res;
}
/* Write LEN bytes from BUF to FD. This is similar to iread(), but
- doesn't bother with select(). Unlike iread(), it makes sure that
- all of BUF is actually written to FD, so callers needn't bother
- with checking that the return value equals to LEN. Instead, you
- should simply check for -1. */
+ unlike iread(), it makes sure that all of BUF is actually written
+ to FD, so callers needn't bother with checking that the return
+ value equals to LEN. Instead, you should simply check for -1. */
+
int
iwrite (int fd, char *buf, int len)
{
innermost loop deals with the same during select(). */
while (len > 0)
{
- do
- {
#ifdef HAVE_SELECT
- if (opt.timeout)
- {
- do
- {
- res = select_fd (fd, opt.timeout, 1);
- }
- while (res == -1 && errno == EINTR);
- if (res <= 0)
- {
- /* Set errno to ETIMEDOUT on timeout. */
- if (res == 0)
- /* #### Potentially evil! */
- errno = ETIMEDOUT;
- return -1;
- }
- }
+ if (opt.timeout)
+ if (select_fd (fd, opt.timeout, 1) <= 0)
+ return -1;
#endif
- res = WRITE (fd, buf, len);
- }
+ do
+ res = WRITE (fd, buf, len);
while (res == -1 && errno == EINTR);
if (res <= 0)
break;