}
\f
static int
-resolve_bind_address (const char *host, struct sockaddr *sa, int flags)
+resolve_bind_address (struct sockaddr *sa)
{
struct address_list *al;
- /* #### Shouldn't we do this only once? opt.bind_address won't
- change during a Wget run! */
+ /* Make sure this is called only once. opt.bind_address doesn't
+ change during a Wget run. */
+ static int called, should_bind;
+ static ip_address ip;
+ if (called)
+ {
+ if (should_bind)
+ sockaddr_set_data (sa, &ip, 0);
+ return should_bind;
+ }
+ called = 1;
- al = lookup_host (host, flags | LH_SILENT | LH_PASSIVE);
- if (al == NULL)
+ al = lookup_host_passive (opt.bind_address);
+ if (!al)
{
- /* #### We should print the error message here. */
+ /* #### We should be able to print the error message here. */
logprintf (LOG_NOTQUIET,
_("%s: unable to resolve bind address `%s'; disabling bind.\n"),
exec_name, opt.bind_address);
+ should_bind = 0;
return 0;
}
/* Pick the first address in the list and use it as bind address.
- Perhaps we should try multiple addresses, but I don't think
- that's necessary in practice. */
- sockaddr_set_data (sa, address_list_address_at (al, 0), 0);
+ Perhaps we should try multiple addresses in succession, but I
+ don't think that's necessary in practice. */
+ ip = *address_list_address_at (al, 0);
address_list_release (al);
+
+ sockaddr_set_data (sa, &ip, 0);
+ should_bind = 1;
return 1;
}
\f
address. */
struct sockaddr_storage bind_ss;
struct sockaddr *bind_sa = (struct sockaddr *)&bind_ss;
- if (resolve_bind_address (opt.bind_address, bind_sa, 0))
+ if (resolve_bind_address (bind_sa))
{
if (bind (sock, bind_sa, sockaddr_size (bind_sa)) < 0)
goto err;
/* Mapping between known hosts and to lists of their addresses. */
static struct hash_table *host_name_addresses_map;
+
+#ifdef ENABLE_IPV6
+/* The default IP family for looking up host names. This should be
+ moved to an entry in struct options when we implement the
+ --inet4/--inet6 flags. */
+static int ip_default_family = AF_UNSPEC;
+#endif
\f
/* Lists of addresses. This should eventually be extended to handle
IPv6. */
return ctx.hptr;
}
+/* Print error messages for host errors. */
+static char *
+host_errstr (int error)
+{
+ /* Can't use switch since some of these constants can be equal,
+ which makes the compiler complain about duplicate case
+ values. */
+ if (error == HOST_NOT_FOUND
+ || error == NO_RECOVERY
+ || error == NO_DATA
+ || error == NO_ADDRESS)
+ return _("Host not found");
+ else if (error == TRY_AGAIN)
+ /* Message modeled after what gai_strerror returns in similar
+ circumstances. */
+ return _("Temporary failure in name resolution");
+ else
+ return _("Unknown error");
+}
+
#else /* ENABLE_IPV6 */
struct gaiwt_context {
this function, or set opt.dns_cache to 0 to globally disable
caching.
- FLAGS can be a combination of:
- LH_SILENT - don't print the "resolving ... done" message.
- LH_IPV4_ONLY - return only IPv4 addresses.
- LH_IPV6_ONLY - return only IPv6 addresses. */
+ If SILENT is non-zero, progress messages are not printed. */
struct address_list *
-lookup_host (const char *host, int flags)
+lookup_host (const char *host, int silent)
{
struct address_list *al = NULL;
#ifdef ENABLE_IPV6
int err;
struct addrinfo hints, *res;
-
xzero (hints);
hints.ai_socktype = SOCK_STREAM;
-
- /* Should we inspect opt.<something> directly? */
- if (flags & LH_IPV4_ONLY)
- hints.ai_family = AF_INET;
- else if (flags & LH_IPV6_ONLY)
- hints.ai_family = AF_INET6;
- else
- hints.ai_family = AF_UNSPEC;
+ hints.ai_family = ip_default_family;
#endif
/* First, try to check whether the address is already a numeric
#ifdef ENABLE_IPV6
hints.ai_flags = AI_NUMERICHOST;
- if (flags & LH_PASSIVE)
- hints.ai_flags |= AI_PASSIVE;
/* No need to specify timeout, as we're not resolving HOST, but
merely translating it from the presentation (ASCII) to network
}
}
- if (!(flags & LH_SILENT))
- logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
+ /* No luck with the cache; resolve the host name. */
- /* Host name lookup goes on below. */
+ if (!silent)
+ logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
#ifdef ENABLE_IPV6
hints.ai_flags = 0;
- if (flags & LH_PASSIVE)
- hints.ai_flags |= AI_PASSIVE;
err = getaddrinfo_with_timeout (host, NULL, &hints, &res, opt.dns_timeout);
if (err != 0 || res == NULL)
{
- if (!(flags & LH_SILENT))
+ if (!silent)
logprintf (LOG_VERBOSE, _("failed: %s.\n"),
err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno));
return NULL;
struct hostent *hptr = gethostbyname_with_timeout (host, opt.dns_timeout);
if (!hptr)
{
- if (!(flags & LH_SILENT))
+ if (!silent)
{
if (errno != ETIMEDOUT)
- logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno));
+ logprintf (LOG_VERBOSE, _("failed: %s.\n"),
+ host_errstr (h_errno));
else
logputs (LOG_VERBOSE, _("failed: timed out.\n"));
}
return NULL;
}
- assert (hptr->h_length == 4);
/* Do older systems have h_addr_list? */
al = address_list_from_ipv4_addresses (hptr->h_addr_list);
}
/* Print the addresses determined by DNS lookup, but no more than
three. */
- if (!(flags & LH_SILENT))
+ if (!silent)
{
int i;
int printmax = al->count <= 3 ? al->count : 3;
return al;
}
+
+/* Resolve HOST to get an address for use with bind(2). Do *not* use
+ this for sockets to be used with connect(2).
+
+ This is a function separate from lookup_host because the results it
+ returns are different -- it uses the AI_PASSIVE flag to
+ getaddrinfo. Because of this distinction, it doesn't store the
+ results in the cache. It prints nothing and implements no timeouts
+ because it should normally only be used with local addresses
+ (typically "localhost" or numeric addresses of different local
+ interfaces.)
+
+ Without IPv6, this function just calls lookup_host. */
+
+struct address_list *
+lookup_host_passive (const char *host)
+{
+#ifdef ENABLE_IPV6
+ struct address_list *al = NULL;
+ int err;
+ struct addrinfo hints, *res;
+
+ xzero (hints);
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = ip_default_family;
+ hints.ai_flags = AI_PASSIVE;
+
+ err = getaddrinfo (host, NULL, &hints, &res);
+ if (err != 0 || res == NULL)
+ return NULL;
+ al = address_list_from_addrinfo (res);
+ freeaddrinfo (res);
+ return al;
+#else
+ return lookup_host (host, 1);
+#endif
+}
\f
/* Determine whether a URL is acceptable to be followed, according to
a list of domains to accept. */
return 0;
}
-/* Print error messages for host errors. */
-char *
-herrmsg (int error)
-{
- /* Can't use switch since some constants are equal (at least on my
- system), and the compiler signals "duplicate case value". */
- if (error == HOST_NOT_FOUND
- || error == NO_RECOVERY
- || error == NO_DATA
- || error == NO_ADDRESS
- || error == TRY_AGAIN)
- return _("Host not found");
- else
- return _("Unknown error");
-}
-
static int
host_cleanup_mapper (void *key, void *value, void *arg_ignored)
{