1
0
mirror of https://github.com/moparisthebest/wget synced 2024-07-03 16:38:41 -04:00

[svn] A lot of host name changes.

Published in <sxs3d32856s.fsf@florida.arsdigita.de>.
This commit is contained in:
hniksic 2001-11-25 21:36:33 -08:00
parent f6921edc73
commit 024cb5ed3a
10 changed files with 409 additions and 218 deletions

View File

@ -1,3 +1,34 @@
2001-11-26 Hrvoje Niksic <hniksic@arsdigita.com>
* http.c (last_host_ip): Made into an address_list.
(invalidate_persistent): Release pc_last_host_ip.
(register_persistent): Use lookup_host.
(persistent_available_p): Check for equality of hosts using
address_list_match_all. Call address_list_release.
(http_cleanup): New function.
* ftp.c (getftp): Use lookup_host and connect_to_many.
* http.c (gethttp): Use lookup_host and connect_to_many.
* connect.c (make_connection): Removed.
(connect_to_one): New function.
(connect_to_many): Ditto.
(set_connection_host_name): Ditto.
* host.c (lookup_host): New function; new return type.
(address_list_new): New function.
(address_list_count): Ditto.
(address_list_copy_one): Ditto.
(address_list_delete): Ditto.
(address_list_release): Ditto.
(pretty_print_address): Ditto.
2001-11-26 Hrvoje Niksic <hniksic@arsdigita.com>
* recur.c (retrieve_tree): In case of followed redirection,
blacklist the pre-redirection URL.
2001-11-26 Hrvoje Niksic <hniksic@arsdigita.com> 2001-11-26 Hrvoje Niksic <hniksic@arsdigita.com>
* recur.c (descend_redirect_p): New function. * recur.c (descend_redirect_p): New function.

View File

@ -24,6 +24,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> # include <unistd.h>
#endif #endif
#include <assert.h>
#ifdef WINDOWS #ifdef WINDOWS
# include <winsock.h> # include <winsock.h>
@ -58,43 +59,113 @@ extern int errno;
static int msock = -1; static int msock = -1;
static struct sockaddr *addr; static struct sockaddr *addr;
/* A kludge, but still better than passing the host name all the way
to connect_to_one. */
static const char *connection_host_name;
/* Create an internet connection to HOSTNAME on PORT. The created void
socket will be stored to *SOCK. */ set_connection_host_name (const char *host)
uerr_t {
make_connection (int *sock, char *hostname, unsigned short port) if (host)
assert (connection_host_name == NULL);
else
assert (connection_host_name != NULL);
connection_host_name = host;
}
/* Connect to a remote host whose address has been resolved. */
static int
connect_to_one (unsigned char *addr, unsigned short port, int silent)
{ {
struct sockaddr_in sock_name; struct sockaddr_in sock_name;
int sock, save_errno;
if (!lookup_host (hostname, (unsigned char *)&sock_name.sin_addr))
return HOSTERR;
/* Set port and protocol */ /* Set port and protocol */
sock_name.sin_family = AF_INET; sock_name.sin_family = AF_INET;
sock_name.sin_port = htons (port); sock_name.sin_port = htons (port);
memcpy ((unsigned char *)&sock_name.sin_addr, addr, 4);
if (!silent)
{
char *pretty_addr = pretty_print_address (addr);
if (connection_host_name
&& 0 != strcmp (connection_host_name, pretty_addr))
logprintf (LOG_VERBOSE, _("Connecting to %s[%s]:%hu... "),
connection_host_name, pretty_addr, port);
else
logprintf (LOG_VERBOSE, _("Connecting to %s:%hu... "),
pretty_addr, port);
}
/* Make an internet socket, stream type. */ /* Make an internet socket, stream type. */
if ((*sock = socket (AF_INET, SOCK_STREAM, 0)) == -1) sock = socket (AF_INET, SOCK_STREAM, 0);
return CONSOCKERR; if (sock < 0)
goto out;
if (opt.bind_address != NULL) if (opt.bind_address)
{ {
/* Bind the client side to the requested address. */ /* Bind the client side to the requested address. */
if (bind (*sock, (struct sockaddr *) opt.bind_address, if (bind (sock, (struct sockaddr *)opt.bind_address,
sizeof (*opt.bind_address))) sizeof (*opt.bind_address)))
return CONSOCKERR; {
close (sock);
sock = -1;
goto out;
}
} }
/* Connect the socket to the remote host. */ /* Connect the socket to the remote host. */
if (connect (*sock, (struct sockaddr *) &sock_name, sizeof (sock_name))) if (connect (sock, (struct sockaddr *)&sock_name, sizeof (sock_name)) < 0)
{ {
if (errno == ECONNREFUSED) close (sock);
return CONREFUSED; sock = -1;
else goto out;
return CONERROR;
} }
DEBUGP (("Created fd %d.\n", *sock));
return NOCONERROR; out:
if (sock >= 0)
{
/* Success. */
if (!silent)
logprintf (LOG_VERBOSE, _("connected.\n"));
DEBUGP (("Created socket %d.\n", sock));
}
else
{
save_errno = errno;
if (!silent)
logprintf (LOG_VERBOSE, "failed: %s.\n", strerror (errno));
errno = save_errno;
}
return sock;
}
/* Connect to a remote host whose address has been resolved. */
int
connect_to_many (struct address_list *al, unsigned short port, int silent)
{
int i;
for (i = 0; i < address_list_count (al); i++)
{
unsigned char addr[4];
int sock;
address_list_copy_one (al, i, addr);
sock = connect_to_one (addr, port, silent);
if (sock >= 0)
return sock;
/* Perhaps we should have a way of removing the failing entry
from the address list? */
/* The attempt to connect has failed. Continue with the loop
and try next address. */
}
return -1;
} }
int int

View File

@ -20,8 +20,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef CONNECT_H #ifndef CONNECT_H
#define CONNECT_H #define CONNECT_H
struct address_list;
/* Function declarations */ /* Function declarations */
uerr_t make_connection PARAMS ((int *, char *, unsigned short));
int connect_to_many PARAMS ((struct address_list *, unsigned short, int));
void set_connection_host_name PARAMS ((const char *));
int test_socket_open PARAMS ((int)); int test_socket_open PARAMS ((int));
uerr_t bindport PARAMS ((unsigned short *)); uerr_t bindport PARAMS ((unsigned short *));
uerr_t acceptport PARAMS ((int *)); uerr_t acceptport PARAMS ((int *));

103
src/ftp.c
View File

@ -158,54 +158,33 @@ getftp (struct url *u, long *len, long restval, ccon *con)
else /* cmd & DO_LOGIN */ else /* cmd & DO_LOGIN */
{ {
char type_char; char type_char;
struct address_list *al;
/* Login to the server: */ /* Login to the server: */
/* First: Establish the control connection. */ /* First: Establish the control connection. */
logprintf (LOG_VERBOSE, _("Connecting to %s:%hu... "), u->host, u->port);
err = make_connection (&csock, u->host, u->port); al = lookup_host (u->host, 0);
if (!al)
return HOSTERR;
set_connection_host_name (u->host);
csock = connect_to_many (al, u->port, 0);
set_connection_host_name (NULL);
address_list_release (al);
if (csock < 0)
return errno == ECONNREFUSED ? CONREFUSED : CONERROR;
if (cmd & LEAVE_PENDING) if (cmd & LEAVE_PENDING)
rbuf_initialize (&con->rbuf, csock); rbuf_initialize (&con->rbuf, csock);
else else
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
switch (err)
{
/* Do not close the socket in first several cases, since it
wasn't created at all. */
case HOSTERR:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, "%s: %s\n", u->host, herrmsg (h_errno));
return HOSTERR;
break;
case CONSOCKERR:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
return CONSOCKERR;
break;
case CONREFUSED:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, _("Connection to %s:%hu refused.\n"),
u->host, u->port);
CLOSE (csock);
rbuf_uninitialize (&con->rbuf);
return CONREFUSED;
case CONERROR:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, "connect: %s\n", strerror (errno));
CLOSE (csock);
rbuf_uninitialize (&con->rbuf);
return CONERROR;
break;
default:
DO_NOTHING;
/* #### Hmm? */
}
/* Since this is a new connection, we may safely discard /* Since this is a new connection, we may safely discard
anything left in the buffer. */ anything left in the buffer. */
rbuf_discard (&con->rbuf); rbuf_discard (&con->rbuf);
/* Second: Login with proper USER/PASS sequence. */ /* Second: Login with proper USER/PASS sequence. */
logputs (LOG_VERBOSE, _("connected!\n"));
logprintf (LOG_VERBOSE, _("Logging in as %s ... "), user); logprintf (LOG_VERBOSE, _("Logging in as %s ... "), user);
if (opt.server_response) if (opt.server_response)
logputs (LOG_ALWAYS, "\n"); logputs (LOG_ALWAYS, "\n");
@ -557,52 +536,30 @@ Error in server response, closing control connection.\n"));
} }
if (err==FTPOK) if (err==FTPOK)
{ {
struct address_list *al;
sprintf (thost, "%d.%d.%d.%d", sprintf (thost, "%d.%d.%d.%d",
pasv_addr[0], pasv_addr[1], pasv_addr[2], pasv_addr[3]); pasv_addr[0], pasv_addr[1], pasv_addr[2], pasv_addr[3]);
tport = (pasv_addr[4] << 8) + pasv_addr[5]; tport = (pasv_addr[4] << 8) + pasv_addr[5];
DEBUGP ((_("Will try connecting to %s:%hu.\n"), thost, tport));
err = make_connection (&dtsock, thost, tport); al = lookup_host (thost, 0);
switch (err) if (!al)
{ {
/* Do not close the socket in first several cases,
since it wasn't created at all. */
case HOSTERR:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, "%s: %s\n", thost,
herrmsg (h_errno));
CLOSE (csock); CLOSE (csock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
return HOSTERR; return HOSTERR;
break;
case CONSOCKERR:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
CLOSE (csock);
rbuf_uninitialize (&con->rbuf);
return CONSOCKERR;
break;
case CONREFUSED:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET,
_("Connection to %s:%hu refused.\n"),
thost, tport);
CLOSE (csock);
rbuf_uninitialize (&con->rbuf);
closeport (dtsock);
return CONREFUSED;
case CONERROR:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, "connect: %s\n",
strerror (errno));
CLOSE (csock);
rbuf_uninitialize (&con->rbuf);
closeport (dtsock);
return CONERROR;
break;
default:
/* #### What?! */
DO_NOTHING;
} }
dtsock = connect_to_many (al, tport, 0);
address_list_release (al);
if (dtsock < 0)
{
int save_errno = errno;
CLOSE (csock);
rbuf_uninitialize (&con->rbuf);
return save_errno == ECONNREFUSED ? CONREFUSED : CONERROR;
}
passive_mode_open= 1; /* Flag to avoid accept port */ passive_mode_open= 1; /* Flag to avoid accept port */
if (!opt.server_response) if (!opt.server_response)
logputs (LOG_VERBOSE, _("done. ")); logputs (LOG_VERBOSE, _("done. "));

View File

@ -59,120 +59,199 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
extern int errno; extern int errno;
#endif #endif
/* Mapping between all known hosts to their addresses (n.n.n.n). */ #define IP4_ADDRESS_LENGTH 4
/* #### We should map to *lists* of IP addresses. */ /* Mapping between known hosts and to lists of their addresses. */
struct hash_table *host_name_address_map; struct hash_table *host_name_addresses_map;
#if 0 /* Lists of addresses. This should eventually be extended to handle
IPv6. */
/* This function is no longer used. */ struct address_list {
int count; /* number of adrresses */
unsigned char *buffer; /* buffer which holds all of them. */
/* The same as gethostbyname, but supports internet addresses of the int refcount; /* so we know whether to free it or
form `N.N.N.N'. On some systems gethostbyname() knows how to do not. */
this automatically. */ };
struct hostent *
ngethostbyname (const char *name) #define ADDR_LOCATION(al, index) ((al)->buffer + index * IP4_ADDRESS_LENGTH)
/* Return the number of addresses in the list. */
int
address_list_count (struct address_list *al)
{ {
struct hostent *hp; return al->count;
unsigned long addr;
addr = (unsigned long)inet_addr (name);
if ((int)addr != -1)
hp = gethostbyaddr ((char *)&addr, sizeof (addr), AF_INET);
else
hp = gethostbyname (name);
return hp;
} }
#endif
/* Add host name HOST with the address ADDR_TEXT to the cache. */ /* Copy address number INDEX to IP_STORE. */
void
address_list_copy_one (struct address_list *al, int index,
unsigned char *ip_store)
{
memcpy (ip_store, ADDR_LOCATION (al, index), IP4_ADDRESS_LENGTH);
}
/* Check whether two address lists have all their IPs in common. */
int
address_list_match_all (struct address_list *al1, struct address_list *al2)
{
if (al1 == al2)
return 1;
if (al1->count != al2->count)
return 0;
return 0 == memcmp (al1->buffer, al2->buffer,
al1->count * IP4_ADDRESS_LENGTH);
}
/* Create an address_list out of a NULL-terminated list of addresses,
as returned by gethostbyname. */
static struct address_list *
address_list_new (char **h_addr_list)
{
int count = 0, i;
struct address_list *al = xmalloc (sizeof (struct address_list));
while (h_addr_list[count])
++count;
assert (count > 0);
al->count = count;
al->buffer = xmalloc (count * IP4_ADDRESS_LENGTH);
al->refcount = 1;
for (i = 0; i < count; i++)
memcpy (ADDR_LOCATION (al, i), h_addr_list[i], IP4_ADDRESS_LENGTH);
return al;
}
static void static void
add_host_to_cache (const char *host, const char *addr_text) address_list_delete (struct address_list *al)
{ {
DEBUGP (("Caching %s => %s\n", host, addr_text)); xfree (al->buffer);
xfree (al);
if (!host_name_address_map)
host_name_address_map = make_nocase_string_hash_table (0);
hash_table_put (host_name_address_map,
xstrdup_lower (host), xstrdup (addr_text));
} }
/* Store the address of HOSTNAME, internet-style (four octets in void
network order), to WHERE. First try to get the address from the address_list_release (struct address_list *al)
cache; if it is not available, call the DNS functions and update
the cache.
Return 1 on successful finding of the hostname, 0 otherwise. */
int
lookup_host (const char *hostname, unsigned char *store_ip)
{ {
--al->refcount;
DEBUGP (("Releasing %p (new refcount %d).\n", al, al->refcount));
if (al->refcount <= 0)
{
DEBUGP (("Deleting unused %p.\n", al));
address_list_delete (al);
}
}
/* The same as inet_ntoa, but without the need for a cast, or for
#including the netinet stuff. */
char *
pretty_print_address (const unsigned char *addr)
{
return inet_ntoa (*(struct in_addr *)addr);
}
/* Add host name HOST with the address ADDR_TEXT to the cache.
ADDR_LIST is a NULL-terminated list of addresses, as in struct
hostent. */
static void
cache_host_lookup (const char *host, struct address_list *al)
{
if (!host_name_addresses_map)
host_name_addresses_map = make_nocase_string_hash_table (0);
++al->refcount;
hash_table_put (host_name_addresses_map, xstrdup_lower (host), al);
#ifdef DEBUG
if (opt.debug)
{
int i;
debug_logprintf ("Caching %s =>", host);
for (i = 0; i < al->count; i++)
debug_logprintf (" %s",
pretty_print_address (ADDR_LOCATION (al, i)));
debug_logprintf ("\n");
}
#endif
}
struct address_list *
lookup_host (const char *host, int silent)
{
struct address_list *al = NULL;
unsigned long addr; unsigned long addr;
char *addr_text = NULL;
struct hostent *hptr; struct hostent *hptr;
struct in_addr in;
char *inet_s;
/* If the address is of the form d.d.d.d, no further lookup is /* If the address is of the form d.d.d.d, no further lookup is
needed. */ needed. */
addr = (unsigned long)inet_addr (hostname); addr = (unsigned long)inet_addr (host);
if ((int)addr != -1) if ((int)addr != -1)
{ {
unsigned char tmpstore[IP4_ADDRESS_LENGTH];
char *lst[] = { tmpstore, NULL };
/* ADDR is defined to be in network byte order, which is what /* ADDR is defined to be in network byte order, which is what
this returns, so we can just copy it to STORE_IP. However, this returns, so we can just copy it to STORE_IP. However,
on big endian 64-bit architectures the value will be stored on big endian 64-bit architectures the value will be stored
in the *last*, not first four bytes. OFFSET makes sure that in the *last*, not first four bytes. OFFSET makes sure that
we copy the correct four bytes. */ we copy the correct four bytes. */
int offset; int offset;
have_addr:
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
offset = sizeof (unsigned long) - 4; offset = sizeof (unsigned long) - IP4_ADDRESS_LENGTH;
#else #else
offset = 0; offset = 0;
#endif #endif
memcpy (store_ip, (char *)&addr + offset, 4); memcpy (tmpstore, (char *)&addr + offset, IP4_ADDRESS_LENGTH);
return 1; return address_list_new (lst);
} }
/* By now we know that the host name we got is not of the form /* By now we know that the host name we got is not of the form
d.d.d.d. Try to find it in our cache of host names. */ d.d.d.d. Try to find it in our cache of host names. */
if (host_name_address_map) if (host_name_addresses_map)
addr_text = hash_table_get (host_name_address_map, hostname); al = hash_table_get (host_name_addresses_map, host);
if (addr_text) if (al)
{ {
DEBUGP (("Found %s in host_name_address_map: %s\n", DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
hostname, addr_text)); ++al->refcount;
addr = (unsigned long)inet_addr (addr_text); return al;
goto have_addr;
} }
if (!silent)
logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
/* Look up the host using gethostbyname(). Note that we use /* Look up the host using gethostbyname(). Note that we use
gethostbyname() rather than ngethostbyname(), because we already gethostbyname() rather than ngethostbyname(), because we already
know that the address is not numerical. */ know that the address is not numerical. */
hptr = gethostbyname (hostname); hptr = gethostbyname (host);
if (!hptr) if (!hptr)
return 0; {
if (!silent)
logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno));
return NULL;
}
/* Store the IP address to the desired location. */ if (!silent)
assert (hptr->h_length == 4); logprintf (LOG_VERBOSE, _("done.\n"));
memcpy (store_ip, hptr->h_addr_list[0], hptr->h_length);
/* Now that we've successfully looked up the host, store this al = address_list_new (hptr->h_addr_list);
information in the cache. */
/* Originally, we copied to in.s_addr, but it appears to be missing /* Cache the lookup information. */
on some systems. */ cache_host_lookup (host, al);
memcpy (&in, *hptr->h_addr_list, sizeof (in));
inet_s = inet_ntoa (in);
add_host_to_cache (hostname, inet_s);
return 1; return al;
} }
/* Determine whether a URL is acceptable to be followed, according to /* Determine whether a URL is acceptable to be followed, according to
a list of domains to accept. */ a list of domains to accept. */
int int
@ -231,9 +310,27 @@ herrmsg (int error)
return _("Unknown error"); return _("Unknown error");
} }
static int
host_cleanup_mapper (void *key, void *value, void *arg_ignored)
{
struct address_list *al;
xfree (key); /* host */
al = (struct address_list *)value;
assert (al->refcount == 1);
address_list_delete (al);
return 0;
}
void void
host_cleanup (void) host_cleanup (void)
{ {
free_keys_and_values (host_name_address_map); if (host_name_addresses_map)
hash_table_destroy (host_name_address_map); {
hash_table_map (host_name_addresses_map, host_cleanup_mapper, NULL);
hash_table_destroy (host_name_addresses_map);
host_name_addresses_map = NULL;
}
} }

View File

@ -1,5 +1,5 @@
/* Declarations for host.c /* Declarations for host.c
Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. Copyright (C) 1995, 1996, 1997, 2001 Free Software Foundation, Inc.
This file is part of GNU Wget. This file is part of GNU Wget.
@ -21,12 +21,23 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#define HOST_H #define HOST_H
struct url; struct url;
struct address_list;
/* Function declarations */ /* Function declarations */
struct address_list *lookup_host PARAMS ((const char *, int));
int lookup_host PARAMS ((const char *, unsigned char *));
char *herrmsg PARAMS ((int)); char *herrmsg PARAMS ((int));
int address_list_count PARAMS ((struct address_list *));
void address_list_copy_one PARAMS ((struct address_list *, int,
unsigned char *));
void address_list_release PARAMS ((struct address_list *));
int address_list_match_all PARAMS ((struct address_list *,
struct address_list *));
/* This was originally going to be a macro, but then every caller
would have to #include the netinet stuff. */
char *pretty_print_address PARAMS ((const unsigned char *));
int accept_domain PARAMS ((struct url *)); int accept_domain PARAMS ((struct url *));
int sufmatch PARAMS ((const char **, const char *)); int sufmatch PARAMS ((const char **, const char *));

View File

@ -276,7 +276,7 @@ http_process_connection (const char *hdr, void *arg)
/* Whether a persistent connection is active. */ /* Whether a persistent connection is active. */
static int pc_active_p; static int pc_active_p;
/* Host and port of currently active persistent connection. */ /* Host and port of currently active persistent connection. */
static unsigned char pc_last_host_ip[4]; static struct address_list *pc_last_host_ip;
static unsigned short pc_last_port; static unsigned short pc_last_port;
/* File descriptor of the currently active persistent connection. */ /* File descriptor of the currently active persistent connection. */
@ -301,6 +301,11 @@ invalidate_persistent (void)
#ifdef HAVE_SSL #ifdef HAVE_SSL
pc_active_ssl = 0; pc_active_ssl = 0;
#endif /* HAVE_SSL */ #endif /* HAVE_SSL */
if (pc_last_host_ip != NULL)
{
address_list_release (pc_last_host_ip);
pc_last_host_ip = NULL;
}
DEBUGP (("Invalidating fd %d from further reuse.\n", pc_last_fd)); DEBUGP (("Invalidating fd %d from further reuse.\n", pc_last_fd));
} }
@ -319,8 +324,6 @@ register_persistent (const char *host, unsigned short port, int fd
#endif #endif
) )
{ {
int success;
if (pc_active_p) if (pc_active_p)
{ {
if (pc_last_fd == fd) if (pc_last_fd == fd)
@ -347,10 +350,13 @@ register_persistent (const char *host, unsigned short port, int fd
} }
} }
assert (pc_last_host_ip == NULL);
/* This lookup_host cannot fail, because it has the results in the /* This lookup_host cannot fail, because it has the results in the
cache. */ cache. */
success = lookup_host (host, pc_last_host_ip); pc_last_host_ip = lookup_host (host, 1);
assert (success); assert (pc_last_host_ip != NULL);
pc_last_port = port; pc_last_port = port;
pc_last_fd = fd; pc_last_fd = fd;
pc_active_p = 1; pc_active_p = 1;
@ -371,7 +377,9 @@ persistent_available_p (const char *host, unsigned short port
#endif #endif
) )
{ {
unsigned char this_host_ip[4]; int success;
struct address_list *this_host_ip;
/* First, check whether a persistent connection is active at all. */ /* First, check whether a persistent connection is active at all. */
if (!pc_active_p) if (!pc_active_p)
return 0; return 0;
@ -379,6 +387,7 @@ persistent_available_p (const char *host, unsigned short port
(HOST, PORT) ordered pair. */ (HOST, PORT) ordered pair. */
if (port != pc_last_port) if (port != pc_last_port)
return 0; return 0;
#ifdef HAVE_SSL #ifdef HAVE_SSL
/* Second, a): check if current connection is (not) ssl, too. This /* Second, a): check if current connection is (not) ssl, too. This
test is unlikely to fail because HTTP and HTTPS typicaly use test is unlikely to fail because HTTP and HTTPS typicaly use
@ -388,10 +397,19 @@ persistent_available_p (const char *host, unsigned short port
if (ssl != pc_active_ssl) if (ssl != pc_active_ssl)
return 0; return 0;
#endif /* HAVE_SSL */ #endif /* HAVE_SSL */
if (!lookup_host (host, this_host_ip))
this_host_ip = lookup_host (host, 1);
if (!this_host_ip)
return 0; return 0;
if (memcmp (pc_last_host_ip, this_host_ip, 4))
/* To equate the two host names for the purposes of persistent
connections, they need to share all the IP addresses in the
list. */
success = address_list_match_all (pc_last_host_ip, this_host_ip);
address_list_release (this_host_ip);
if (!success)
return 0; return 0;
/* Third: check whether the connection is still open. This is /* Third: check whether the connection is still open. This is
important because most server implement a liberal (short) timeout important because most server implement a liberal (short) timeout
on persistent connections. Wget can of course always reconnect on persistent connections. Wget can of course always reconnect
@ -521,7 +539,6 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
int sock, hcount, num_written, all_length, statcode; int sock, hcount, num_written, all_length, statcode;
long contlen, contrange; long contlen, contrange;
struct url *conn; struct url *conn;
uerr_t err;
FILE *fp; FILE *fp;
int auth_tried_already; int auth_tried_already;
struct rbuf rbuf; struct rbuf rbuf;
@ -622,42 +639,17 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
#endif /* HAVE_SSL */ #endif /* HAVE_SSL */
) )
{ {
logprintf (LOG_VERBOSE, _("Connecting to %s:%hu... "), struct address_list *al = lookup_host (conn->host, 0);
conn->host, conn->port); if (!al)
err = make_connection (&sock, conn->host, conn->port); return HOSTERR;
switch (err) set_connection_host_name (conn->host);
{ sock = connect_to_many (al, conn->port, 0);
case HOSTERR: set_connection_host_name (NULL);
logputs (LOG_VERBOSE, "\n"); address_list_release (al);
logprintf (LOG_NOTQUIET, "%s: %s.\n", conn->host, herrmsg (h_errno));
return HOSTERR; if (sock < 0)
break; return errno == ECONNREFUSED ? CONREFUSED : CONERROR;
case CONSOCKERR:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
return CONSOCKERR;
break;
case CONREFUSED:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET,
_("Connection to %s:%hu refused.\n"), conn->host,
conn->port);
CLOSE (sock);
return CONREFUSED;
case CONERROR:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, "connect: %s\n", strerror (errno));
CLOSE (sock);
return CONERROR;
break;
case NOCONERROR:
/* Everything is fine! */
logputs (LOG_VERBOSE, _("connected!\n"));
break;
default:
abort ();
break;
}
#ifdef HAVE_SSL #ifdef HAVE_SSL
if (conn->scheme == SCHEME_HTTPS) if (conn->scheme == SCHEME_HTTPS)
if (connect_ssl (&ssl, ssl_ctx,sock) != 0) if (connect_ssl (&ssl, ssl_ctx,sock) != 0)
@ -2334,3 +2326,10 @@ create_authorization_line (const char *au, const char *user,
#endif /* USE_DIGEST */ #endif /* USE_DIGEST */
return wwwauth; return wwwauth;
} }
void
http_cleanup (void)
{
if (pc_last_host_ip)
address_list_release (pc_last_host_ip);
}

View File

@ -521,17 +521,22 @@ static int myatoi PARAMS ((const char *s));
static int static int
cmd_address (const char *com, const char *val, void *closure) cmd_address (const char *com, const char *val, void *closure)
{ {
struct address_list *al;
struct sockaddr_in sin; struct sockaddr_in sin;
struct sockaddr_in **target = (struct sockaddr_in **)closure; struct sockaddr_in **target = (struct sockaddr_in **)closure;
memset (&sin, '\0', sizeof (sin)); memset (&sin, '\0', sizeof (sin));
if (!lookup_host (val, (unsigned char *)&sin.sin_addr)) al = lookup_host (val, 1);
if (!al)
{ {
fprintf (stderr, _("%s: %s: Cannot convert `%s' to an IP address.\n"), fprintf (stderr, _("%s: %s: Cannot convert `%s' to an IP address.\n"),
exec_name, com, val); exec_name, com, val);
return 0; return 0;
} }
address_list_copy_one (al, 0, (unsigned char *)&sin.sin_addr);
address_list_release (al);
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
sin.sin_port = 0; sin.sin_port = 0;
@ -1011,6 +1016,7 @@ check_user_specified_header (const char *s)
void cleanup_html_url PARAMS ((void)); void cleanup_html_url PARAMS ((void));
void res_cleanup PARAMS ((void)); void res_cleanup PARAMS ((void));
void downloaded_files_free PARAMS ((void)); void downloaded_files_free PARAMS ((void));
void http_cleanup PARAMS ((void));
/* Free the memory allocated by global variables. */ /* Free the memory allocated by global variables. */
@ -1033,14 +1039,16 @@ cleanup (void)
#ifdef DEBUG_MALLOC #ifdef DEBUG_MALLOC
recursive_cleanup (); recursive_cleanup ();
res_cleanup (); res_cleanup ();
http_cleanup ();
cleanup_html_url ();
downloaded_files_free ();
cookies_cleanup ();
host_cleanup (); host_cleanup ();
{ {
extern acc_t *netrc_list; extern acc_t *netrc_list;
free_netrc (netrc_list); free_netrc (netrc_list);
} }
cleanup_html_url ();
downloaded_files_free ();
cookies_cleanup ();
FREE_MAYBE (opt.lfilename); FREE_MAYBE (opt.lfilename);
xfree (opt.dir_prefix); xfree (opt.dir_prefix);
FREE_MAYBE (opt.input_filename); FREE_MAYBE (opt.input_filename);

View File

@ -241,6 +241,10 @@ retrieve_tree (const char *start_url)
if (!descend_redirect_p (redirected, url, depth, if (!descend_redirect_p (redirected, url, depth,
start_url_parsed, blacklist)) start_url_parsed, blacklist))
descend = 0; descend = 0;
else
/* Make sure that the old pre-redirect form gets
blacklisted. */
string_set_add (blacklist, url);
} }
xfree (url); xfree (url);

View File

@ -427,13 +427,21 @@ retrieve_url (const char *origurl, char **file, char **newloc,
FREE_MAYBE (local_file); FREE_MAYBE (local_file);
url_free (u); url_free (u);
if (redirections)
string_set_free (redirections);
if (newloc) if (redirections)
*newloc = url; {
string_set_free (redirections);
if (newloc)
*newloc = url;
else
xfree (url);
}
else else
xfree (url); {
if (newloc)
*newloc = NULL;
xfree (url);
}
++global_download_count; ++global_download_count;