mirror of
https://github.com/moparisthebest/wget
synced 2024-07-03 16:38:41 -04:00
[svn] Added reordering of addresses to try IPv4 first and the associated
--prefer-family switch.
This commit is contained in:
parent
e14d2b8115
commit
cf994330a3
@ -1,3 +1,7 @@
|
|||||||
|
2005-04-24 Hrvoje Niksic <hniksic@xemacs.org>
|
||||||
|
|
||||||
|
* wget.texi (Download Options): Document --prefer-family.
|
||||||
|
|
||||||
2005-04-24 Hrvoje Niksic <hniksic@xemacs.org>
|
2005-04-24 Hrvoje Niksic <hniksic@xemacs.org>
|
||||||
|
|
||||||
* wget.texi (Download Options): Don't claim that -6 accepts mapped
|
* wget.texi (Download Options): Don't claim that -6 accepts mapped
|
||||||
|
@ -900,6 +900,27 @@ or to deal with broken network configuration. Only one of
|
|||||||
@samp{--inet6-only} and @samp{--inet4-only} may be specified in the
|
@samp{--inet6-only} and @samp{--inet4-only} may be specified in the
|
||||||
same command. Neither option is available in Wget compiled without
|
same command. Neither option is available in Wget compiled without
|
||||||
IPv6 support.
|
IPv6 support.
|
||||||
|
|
||||||
|
@item --prefer-family=IPv4/IPv6/none
|
||||||
|
When given a choice of several addresses, connect to the addresses
|
||||||
|
with specified address family first. IPv4 addresses are preferred by
|
||||||
|
default.
|
||||||
|
|
||||||
|
This avoids spurious errors and correct attempts when accessing hosts
|
||||||
|
that resolve to both IPv6 and IPv4 addresses from IPv4 networks. For
|
||||||
|
example, @samp{www.kame.net} resolves to
|
||||||
|
@samp{2001:200:0:8002:203:47ff:fea5:3085} and to
|
||||||
|
@samp{203.178.141.194}. When the preferred family is @code{IPv4}, the
|
||||||
|
IPv4 address is used first; when the preferred family is @code{IPv6},
|
||||||
|
the IPv6 address is used first; if the specified value is @code{none},
|
||||||
|
the address order returned by DNS is used without change.
|
||||||
|
|
||||||
|
Unlike @samp{-4} and @samp{-6}, this option doesn't forbid access to
|
||||||
|
any address family, it only changes the @emph{order} in which the
|
||||||
|
addresses are accessed. Also note that the reordering performed by
|
||||||
|
this option is @dfn{stable}---it doesn't affect order of addresses of
|
||||||
|
the same family. That is, the relative order of all IPv4 addresses
|
||||||
|
and of all IPv6 addresses remains intact in all cases.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@node Directory Options
|
@node Directory Options
|
||||||
@ -2536,6 +2557,12 @@ the request body. The same as @samp{--post-data}.
|
|||||||
Use POST as the method for all HTTP requests and send the contents of
|
Use POST as the method for all HTTP requests and send the contents of
|
||||||
@var{file} in the request body. The same as @samp{--post-file}.
|
@var{file} in the request body. The same as @samp{--post-file}.
|
||||||
|
|
||||||
|
@item prefer_family = IPv4/IPv6/none
|
||||||
|
When given a choice of several addresses, connect to the addresses
|
||||||
|
with specified address family first. IPv4 addresses are preferred by
|
||||||
|
default. The same as @samp{--prefer-family}, which see for a detailed
|
||||||
|
discussion of why this is useful.
|
||||||
|
|
||||||
@item progress = @var{string}
|
@item progress = @var{string}
|
||||||
Set the type of the progress indicator. Legal types are ``dot'' and
|
Set the type of the progress indicator. Legal types are ``dot'' and
|
||||||
``bar''.
|
``bar''.
|
||||||
@ -3548,6 +3575,12 @@ Mauro Tortonesi,
|
|||||||
Dave Turner,
|
Dave Turner,
|
||||||
Gisle Vanem,
|
Gisle Vanem,
|
||||||
Russell Vincent,
|
Russell Vincent,
|
||||||
|
@iftex
|
||||||
|
@v{Z}eljko Vrba,
|
||||||
|
@end iftex
|
||||||
|
@ifnottex
|
||||||
|
Zeljko Vrba,
|
||||||
|
@end ifnottex
|
||||||
Charles G Waldman,
|
Charles G Waldman,
|
||||||
Douglas E. Wegscheid,
|
Douglas E. Wegscheid,
|
||||||
YAMAZAKI Makoto,
|
YAMAZAKI Makoto,
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
2005-04-24 Hrvoje Niksic <hniksic@xemacs.org>
|
||||||
|
|
||||||
|
* host.c (cmp_prefer_ipv4): New function.
|
||||||
|
(cmp_prefer_ipv6): New function.
|
||||||
|
(lookup_host): Use the appropriate comparator according to
|
||||||
|
opt.prefer_family.
|
||||||
|
|
||||||
|
* init.c: New option prefer_family.
|
||||||
|
|
||||||
|
* host.c (is_valid_ipv6_address): Spell NS_* constants in lower
|
||||||
|
case to avoid clash with system headers.
|
||||||
|
(lookup_host): Reorder the addresses so that IPv4 ones come first.
|
||||||
|
|
||||||
|
* utils.c (stable_sort): New function.
|
||||||
|
|
||||||
2005-04-24 Hrvoje Niksic <hniksic@xemacs.org>
|
2005-04-24 Hrvoje Niksic <hniksic@xemacs.org>
|
||||||
|
|
||||||
* connect.c (retryable_socket_connect_error): Return 0 for
|
* connect.c (retryable_socket_connect_error): Return 0 for
|
||||||
|
70
src/host.c
70
src/host.c
@ -239,6 +239,32 @@ address_list_from_addrinfo (const struct addrinfo *ai)
|
|||||||
return al;
|
return al;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IS_IPV4(addr) (((const ip_address *) addr)->type == IPV4_ADDRESS)
|
||||||
|
|
||||||
|
/* Compare two IP addresses by type, giving preference to the IPv4
|
||||||
|
address (sorting it first). In other words, return -1 if ADDR1 is
|
||||||
|
IPv4 and ADDR2 is IPv6, +1 if ADDR1 is IPv6 and ADDR2 is IPv4, and
|
||||||
|
0 otherwise.
|
||||||
|
|
||||||
|
This is intended to be used as the comparator arg to a qsort-like
|
||||||
|
sorting function, which is why it accepts generic pointers. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmp_prefer_ipv4 (const void *addr1, const void *addr2)
|
||||||
|
{
|
||||||
|
return !IS_IPV4 (addr1) - !IS_IPV4 (addr2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IS_IPV6(addr) (((const ip_address *) addr)->type == IPV6_ADDRESS)
|
||||||
|
|
||||||
|
/* Like the above, but give preference to the IPv6 address. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmp_prefer_ipv6 (const void *addr1, const void *addr2)
|
||||||
|
{
|
||||||
|
return !IS_IPV6 (addr1) - !IS_IPV6 (addr2);
|
||||||
|
}
|
||||||
|
|
||||||
#else /* not ENABLE_IPV6 */
|
#else /* not ENABLE_IPV6 */
|
||||||
|
|
||||||
/* Create an address_list from a NULL-terminated vector of IPv4
|
/* Create an address_list from a NULL-terminated vector of IPv4
|
||||||
@ -473,10 +499,11 @@ is_valid_ipv4_address (const char *str, const char *end)
|
|||||||
int
|
int
|
||||||
is_valid_ipv6_address (const char *str, const char *end)
|
is_valid_ipv6_address (const char *str, const char *end)
|
||||||
{
|
{
|
||||||
|
/* Use lower-case for these to avoid clash with system headers. */
|
||||||
enum {
|
enum {
|
||||||
NS_INADDRSZ = 4,
|
ns_inaddrsz = 4,
|
||||||
NS_IN6ADDRSZ = 16,
|
ns_in6addrsz = 16,
|
||||||
NS_INT16SZ = 2
|
ns_int16sz = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *curtok;
|
const char *curtok;
|
||||||
@ -531,19 +558,19 @@ is_valid_ipv6_address (const char *str, const char *end)
|
|||||||
}
|
}
|
||||||
else if (str == end)
|
else if (str == end)
|
||||||
return 0;
|
return 0;
|
||||||
if (tp > NS_IN6ADDRSZ - NS_INT16SZ)
|
if (tp > ns_in6addrsz - ns_int16sz)
|
||||||
return 0;
|
return 0;
|
||||||
tp += NS_INT16SZ;
|
tp += ns_int16sz;
|
||||||
saw_xdigit = 0;
|
saw_xdigit = 0;
|
||||||
val = 0;
|
val = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if ch is a dot ... */
|
/* if ch is a dot ... */
|
||||||
if (ch == '.' && (tp <= NS_IN6ADDRSZ - NS_INADDRSZ)
|
if (ch == '.' && (tp <= ns_in6addrsz - ns_inaddrsz)
|
||||||
&& is_valid_ipv4_address (curtok, end) == 1)
|
&& is_valid_ipv4_address (curtok, end) == 1)
|
||||||
{
|
{
|
||||||
tp += NS_INADDRSZ;
|
tp += ns_inaddrsz;
|
||||||
saw_xdigit = 0;
|
saw_xdigit = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -553,19 +580,19 @@ is_valid_ipv6_address (const char *str, const char *end)
|
|||||||
|
|
||||||
if (saw_xdigit == 1)
|
if (saw_xdigit == 1)
|
||||||
{
|
{
|
||||||
if (tp > NS_IN6ADDRSZ - NS_INT16SZ)
|
if (tp > ns_in6addrsz - ns_int16sz)
|
||||||
return 0;
|
return 0;
|
||||||
tp += NS_INT16SZ;
|
tp += ns_int16sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (colonp != NULL)
|
if (colonp != NULL)
|
||||||
{
|
{
|
||||||
if (tp == NS_IN6ADDRSZ)
|
if (tp == ns_in6addrsz)
|
||||||
return 0;
|
return 0;
|
||||||
tp = NS_IN6ADDRSZ;
|
tp = ns_in6addrsz;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tp != NS_IN6ADDRSZ)
|
if (tp != ns_in6addrsz)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -640,15 +667,20 @@ cache_remove (const char *host)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look up HOST in DNS and return a list of IP addresses. The
|
/* Look up HOST in DNS and return a list of IP addresses.
|
||||||
addresses in the list are in the same order in which
|
|
||||||
gethostbyname/getaddrinfo returned them.
|
|
||||||
|
|
||||||
This function caches its result so that, if the same host is passed
|
This function caches its result so that, if the same host is passed
|
||||||
the second time, the addresses are returned without DNS lookup.
|
the second time, the addresses are returned without DNS lookup.
|
||||||
(Use LH_REFRESH to force lookup, or set opt.dns_cache to 0 to
|
(Use LH_REFRESH to force lookup, or set opt.dns_cache to 0 to
|
||||||
globally disable caching.)
|
globally disable caching.)
|
||||||
|
|
||||||
|
The order of the returned addresses is affected by the setting of
|
||||||
|
opt.prefer_family: if it is set to prefer_ipv4, IPv4 addresses are
|
||||||
|
placed at the beginning; if it is prefer_ipv6, IPv6 ones are placed
|
||||||
|
at the beginning; otherwise, the order is left intact. The
|
||||||
|
relative order of addresses with the same family is left
|
||||||
|
undisturbed in either case.
|
||||||
|
|
||||||
FLAGS can be a combination of:
|
FLAGS can be a combination of:
|
||||||
LH_SILENT - don't print the "resolving ... done" messages.
|
LH_SILENT - don't print the "resolving ... done" messages.
|
||||||
LH_BIND - resolve addresses for use with bind, which under
|
LH_BIND - resolve addresses for use with bind, which under
|
||||||
@ -778,6 +810,14 @@ lookup_host (const char *host, int flags)
|
|||||||
_("failed: No IPv4/IPv6 addresses for host.\n"));
|
_("failed: No IPv4/IPv6 addresses for host.\n"));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reorder addresses so that IPv4 ones (or IPv6 ones, as per
|
||||||
|
--prefer-family) come first. Sorting is stable so the order of
|
||||||
|
the addresses with the same family is undisturbed. */
|
||||||
|
if (al->count > 1 && opt.prefer_family != prefer_none)
|
||||||
|
stable_sort (al->addresses, al->count, sizeof (ip_address),
|
||||||
|
opt.prefer_family == prefer_ipv4
|
||||||
|
? cmp_prefer_ipv4 : cmp_prefer_ipv6);
|
||||||
}
|
}
|
||||||
#else /* not ENABLE_IPV6 */
|
#else /* not ENABLE_IPV6 */
|
||||||
{
|
{
|
||||||
|
28
src/init.c
28
src/init.c
@ -88,6 +88,7 @@ CMD_DECLARE (cmd_spec_dirstruct);
|
|||||||
CMD_DECLARE (cmd_spec_header);
|
CMD_DECLARE (cmd_spec_header);
|
||||||
CMD_DECLARE (cmd_spec_htmlify);
|
CMD_DECLARE (cmd_spec_htmlify);
|
||||||
CMD_DECLARE (cmd_spec_mirror);
|
CMD_DECLARE (cmd_spec_mirror);
|
||||||
|
CMD_DECLARE (cmd_spec_prefer_family);
|
||||||
CMD_DECLARE (cmd_spec_progress);
|
CMD_DECLARE (cmd_spec_progress);
|
||||||
CMD_DECLARE (cmd_spec_recursive);
|
CMD_DECLARE (cmd_spec_recursive);
|
||||||
CMD_DECLARE (cmd_spec_restrict_file_names);
|
CMD_DECLARE (cmd_spec_restrict_file_names);
|
||||||
@ -177,6 +178,7 @@ static struct {
|
|||||||
{ "passiveftp", &opt.ftp_pasv, cmd_lockable_boolean },
|
{ "passiveftp", &opt.ftp_pasv, cmd_lockable_boolean },
|
||||||
{ "postdata", &opt.post_data, cmd_string },
|
{ "postdata", &opt.post_data, cmd_string },
|
||||||
{ "postfile", &opt.post_file_name, cmd_file },
|
{ "postfile", &opt.post_file_name, cmd_file },
|
||||||
|
{ "preferfamily", NULL, cmd_spec_prefer_family },
|
||||||
{ "preservepermissions", &opt.preserve_perm, cmd_boolean },
|
{ "preservepermissions", &opt.preserve_perm, cmd_boolean },
|
||||||
{ "progress", &opt.progress_type, cmd_spec_progress },
|
{ "progress", &opt.progress_type, cmd_spec_progress },
|
||||||
{ "protocoldirectories", &opt.protocol_directories, cmd_boolean },
|
{ "protocoldirectories", &opt.protocol_directories, cmd_boolean },
|
||||||
@ -1072,6 +1074,32 @@ cmd_spec_mirror (const char *com, const char *val, void *closure)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Validate --prefer-family and set the choice. Allowed values are
|
||||||
|
"IPv4", "IPv6", and "none". */
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmd_spec_prefer_family (const char *com, const char *val, void *closure)
|
||||||
|
{
|
||||||
|
if (0 == strcasecmp (val, "ipv4"))
|
||||||
|
{
|
||||||
|
opt.prefer_family = prefer_ipv4;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (0 == strcasecmp (val, "ipv6"))
|
||||||
|
{
|
||||||
|
opt.prefer_family = prefer_ipv6;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (0 == strcasecmp (val, "none"))
|
||||||
|
{
|
||||||
|
opt.prefer_family = prefer_none;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fprintf (stderr, _("%s: %s: Invalid preferred family `%s'.\n"),
|
||||||
|
exec_name, com, val);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set progress.type to VAL, but verify that it's a valid progress
|
/* Set progress.type to VAL, but verify that it's a valid progress
|
||||||
implementation before that. */
|
implementation before that. */
|
||||||
|
|
||||||
|
@ -214,6 +214,7 @@ struct cmdline_option option_data[] =
|
|||||||
{ "passive-ftp", 0, OPT_BOOLEAN, "passiveftp", -1 },
|
{ "passive-ftp", 0, OPT_BOOLEAN, "passiveftp", -1 },
|
||||||
{ "post-data", 0, OPT_VALUE, "postdata", -1 },
|
{ "post-data", 0, OPT_VALUE, "postdata", -1 },
|
||||||
{ "post-file", 0, OPT_VALUE, "postfile", -1 },
|
{ "post-file", 0, OPT_VALUE, "postfile", -1 },
|
||||||
|
{ "prefer-family", 0, OPT_VALUE, "preferfamily", -1 },
|
||||||
{ "preserve-permissions", 0, OPT_BOOLEAN, "preservepermissions", -1 },
|
{ "preserve-permissions", 0, OPT_BOOLEAN, "preservepermissions", -1 },
|
||||||
{ "progress", 0, OPT_VALUE, "progress", -1 },
|
{ "progress", 0, OPT_VALUE, "progress", -1 },
|
||||||
{ "protocol-directories", 0, OPT_BOOLEAN, "protocoldirectories", -1 },
|
{ "protocol-directories", 0, OPT_BOOLEAN, "protocoldirectories", -1 },
|
||||||
@ -465,6 +466,9 @@ Download:\n"),
|
|||||||
-4, --inet4-only connect only to IPv4 addresses.\n"),
|
-4, --inet4-only connect only to IPv4 addresses.\n"),
|
||||||
N_("\
|
N_("\
|
||||||
-6, --inet6-only connect only to IPv6 addresses.\n"),
|
-6, --inet6-only connect only to IPv6 addresses.\n"),
|
||||||
|
N_("\
|
||||||
|
--prefer-family=FAMILY connect first to addresses of specified family,\n\
|
||||||
|
one of IPv6, IPv4, or none.\n"),
|
||||||
#endif
|
#endif
|
||||||
"\n",
|
"\n",
|
||||||
|
|
||||||
|
@ -197,6 +197,12 @@ struct options
|
|||||||
int ipv4_only; /* IPv4 connections have been requested. */
|
int ipv4_only; /* IPv4 connections have been requested. */
|
||||||
int ipv6_only; /* IPv4 connections have been requested. */
|
int ipv6_only; /* IPv4 connections have been requested. */
|
||||||
#endif
|
#endif
|
||||||
|
enum {
|
||||||
|
prefer_ipv4,
|
||||||
|
prefer_ipv6,
|
||||||
|
prefer_none
|
||||||
|
} prefer_family; /* preferred address family when more
|
||||||
|
than one type is available */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct options opt;
|
extern struct options opt;
|
||||||
|
46
src/utils.c
46
src/utils.c
@ -1975,3 +1975,49 @@ base64_decode (const char *base64, char *to)
|
|||||||
#undef IS_ASCII
|
#undef IS_ASCII
|
||||||
#undef IS_BASE64
|
#undef IS_BASE64
|
||||||
#undef NEXT_BASE64_CHAR
|
#undef NEXT_BASE64_CHAR
|
||||||
|
|
||||||
|
/* Simple merge sort for use by stable_sort. Implementation courtesy
|
||||||
|
Zeljko Vrba. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
mergesort_internal (void *base, void *temp, size_t size, size_t from, size_t to,
|
||||||
|
int (*cmpfun) PARAMS ((const void *, const void *)))
|
||||||
|
{
|
||||||
|
#define ELT(array, pos) ((char *)(array) + (pos) * size)
|
||||||
|
if (from < to)
|
||||||
|
{
|
||||||
|
size_t i, j, k;
|
||||||
|
size_t mid = (to + from) / 2;
|
||||||
|
mergesort_internal (base, temp, size, from, mid, cmpfun);
|
||||||
|
mergesort_internal (base, temp, size, mid + 1, to, cmpfun);
|
||||||
|
i = from;
|
||||||
|
j = mid + 1;
|
||||||
|
for (k = from; (i <= mid) && (j <= to); k++)
|
||||||
|
if (cmpfun (ELT (base, i), ELT (base, j)) <= 0)
|
||||||
|
memcpy (ELT (temp, k), ELT (base, i++), size);
|
||||||
|
else
|
||||||
|
memcpy (ELT (temp, k), ELT (base, j++), size);
|
||||||
|
while (i <= mid)
|
||||||
|
memcpy (ELT (temp, k++), ELT (base, i++), size);
|
||||||
|
while (j <= to)
|
||||||
|
memcpy (ELT (temp, k++), ELT (base, j++), size);
|
||||||
|
for (k = from; k <= to; k++)
|
||||||
|
memcpy (ELT (base, k), ELT (temp, k), size);
|
||||||
|
}
|
||||||
|
#undef ELT
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stable sort with interface exactly like standard library's qsort.
|
||||||
|
Uses mergesort internally, allocating temporary storage with
|
||||||
|
alloca. */
|
||||||
|
|
||||||
|
void
|
||||||
|
stable_sort (void *base, size_t nmemb, size_t size,
|
||||||
|
int (*cmpfun) PARAMS ((const void *, const void *)))
|
||||||
|
{
|
||||||
|
if (size > 1)
|
||||||
|
{
|
||||||
|
void *temp = alloca (nmemb * size * sizeof (void *));
|
||||||
|
mergesort_internal (base, temp, size, 0, nmemb - 1, cmpfun);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -119,4 +119,7 @@ void xsleep PARAMS ((double));
|
|||||||
int base64_encode PARAMS ((const char *, int, char *));
|
int base64_encode PARAMS ((const char *, int, char *));
|
||||||
int base64_decode PARAMS ((const char *, char *));
|
int base64_decode PARAMS ((const char *, char *));
|
||||||
|
|
||||||
|
void stable_sort PARAMS ((void *, size_t, size_t,
|
||||||
|
int (*) (const void *, const void *)));
|
||||||
|
|
||||||
#endif /* UTILS_H */
|
#endif /* UTILS_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user