mirror of
https://github.com/mirror/wget.git
synced 2025-01-21 09:41:06 +08:00
[svn] Replace conaddr with socket_ip_address.
This commit is contained in:
parent
fef88bd179
commit
d7e592d797
@ -1,3 +1,25 @@
|
||||
2003-11-08 Hrvoje Niksic <hniksic@xemacs.org>
|
||||
|
||||
* http.c (persistent_available_p): Instead of matching all the
|
||||
addresses of HOST and last host, determine the peer's IP address
|
||||
with socket_ip_address and see if that address is one of those
|
||||
HOST resolves to.
|
||||
|
||||
* host.c (address_list_match_all): Removed.
|
||||
(address_list_find): New function, finds an IP address in the
|
||||
address list.
|
||||
|
||||
* ftp.c (ftp_do_pasv): Get the peer's address here, and pass it to
|
||||
ftp_epsv so it doesn't need to call getpeername.
|
||||
|
||||
* ftp-basic.c (ftp_port): Use socket_ip_address instead of
|
||||
getpeername.
|
||||
(ftp_lprt): Ditto.
|
||||
|
||||
* connect.c (socket_ip_address): Replaces conaddr, generalized to
|
||||
either get peer's or local address.
|
||||
(sockaddr_get_data): Made local to this file.
|
||||
|
||||
2003-11-08 Hrvoje Niksic <hniksic@xemacs.org>
|
||||
|
||||
* hash.c (HASH_POSITION): Explicitly accept the hash function.
|
||||
|
@ -106,7 +106,7 @@ sockaddr_set_data (struct sockaddr *sa, const ip_address *ip, int port)
|
||||
you're not interested in one or the other information, pass NULL as
|
||||
the pointer. */
|
||||
|
||||
void
|
||||
static void
|
||||
sockaddr_get_data (const struct sockaddr *sa, ip_address *ip, int *port)
|
||||
{
|
||||
switch (sa->sa_family)
|
||||
@ -510,16 +510,28 @@ acceptport (int local_sock, int *sock)
|
||||
return ACCEPTOK;
|
||||
}
|
||||
|
||||
/* Return the local IP address associated with the connection on FD. */
|
||||
/* Get the IP address associated with the connection on FD and store
|
||||
it to IP. Return 1 on success, 0 otherwise.
|
||||
|
||||
If ENDPOINT is ENDPOINT_LOCAL, it returns the address of the local
|
||||
(client) side of the socket. Else if ENDPOINT is ENDPOINT_PEER, it
|
||||
returns the address of the remote (peer's) side of the socket. */
|
||||
|
||||
int
|
||||
conaddr (int fd, ip_address *ip)
|
||||
socket_ip_address (int sock, ip_address *ip, int endpoint)
|
||||
{
|
||||
struct sockaddr_storage storage;
|
||||
struct sockaddr *sockaddr = (struct sockaddr *)&storage;
|
||||
socklen_t addrlen = sizeof (storage);
|
||||
int ret;
|
||||
|
||||
if (getsockname (fd, sockaddr, &addrlen) < 0)
|
||||
if (endpoint == ENDPOINT_LOCAL)
|
||||
ret = getsockname (sock, sockaddr, &addrlen);
|
||||
else if (endpoint == ENDPOINT_PEER)
|
||||
ret = getpeername (sock, sockaddr, &addrlen);
|
||||
else
|
||||
abort ();
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
switch (sockaddr->sa_family)
|
||||
|
@ -51,10 +51,14 @@ enum {
|
||||
int connect_to_host PARAMS ((const char *, int));
|
||||
int connect_to_ip PARAMS ((const ip_address *, int, const char *));
|
||||
|
||||
void sockaddr_get_data PARAMS ((const struct sockaddr *, ip_address *, int *));
|
||||
uerr_t bindport PARAMS ((const ip_address *, int *, int *));
|
||||
uerr_t acceptport PARAMS ((int, int *));
|
||||
int conaddr PARAMS ((int, ip_address *));
|
||||
|
||||
enum {
|
||||
ENDPOINT_LOCAL,
|
||||
ENDPOINT_PEER
|
||||
};
|
||||
int socket_ip_address PARAMS ((int, ip_address *, int));
|
||||
|
||||
/* Flags for select_fd's WAIT_FOR argument. */
|
||||
enum {
|
||||
|
@ -285,7 +285,7 @@ ftp_port (struct rbuf *rbuf, int *local_sock)
|
||||
assert (rbuf_initialized_p (rbuf));
|
||||
|
||||
/* Get the address of this side of the connection. */
|
||||
if (!conaddr (RBUF_FD (rbuf), &addr))
|
||||
if (!socket_ip_address (RBUF_FD (rbuf), &addr, ENDPOINT_LOCAL))
|
||||
return BINDERR;
|
||||
|
||||
assert (addr.type == IPV4_ADDRESS);
|
||||
@ -382,7 +382,7 @@ ftp_lprt (struct rbuf *rbuf, int *local_sock)
|
||||
assert (rbuf_initialized_p (rbuf));
|
||||
|
||||
/* Get the address of this side of the connection. */
|
||||
if (!conaddr (RBUF_FD (rbuf), &addr))
|
||||
if (!socket_ip_address (RBUF_FD (rbuf), &addr, ENDPOINT_LOCAL))
|
||||
return BINDERR;
|
||||
|
||||
assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
|
||||
@ -466,7 +466,7 @@ ftp_eprt (struct rbuf *rbuf, int *local_sock)
|
||||
assert (rbuf_initialized_p(rbuf));
|
||||
|
||||
/* Get the address of this side of the connection. */
|
||||
if (!conaddr (RBUF_FD (rbuf), &addr))
|
||||
if (!socket_ip_address (RBUF_FD (rbuf), &addr, ENDPOINT_LOCAL))
|
||||
return BINDERR;
|
||||
|
||||
assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
|
||||
@ -756,27 +756,18 @@ ftp_epsv (struct rbuf *rbuf, ip_address *ip, int *port)
|
||||
int nwritten, i;
|
||||
uerr_t err;
|
||||
int tport;
|
||||
socklen_t addrlen;
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr *sa = (struct sockaddr *)&ss;
|
||||
|
||||
assert (rbuf != NULL);
|
||||
assert (rbuf_initialized_p(rbuf));
|
||||
assert (ip != NULL);
|
||||
assert (port != NULL);
|
||||
|
||||
addrlen = sizeof (ss);
|
||||
if (getpeername (rbuf->fd, sa, &addrlen) < 0)
|
||||
/* Mauro Tortonesi: HOW DO WE HANDLE THIS ERROR? */
|
||||
return CONPORTERR;
|
||||
|
||||
assert (sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
|
||||
|
||||
sockaddr_get_data (sa, ip, NULL);
|
||||
/* IP already contains the IP address of the control connection's
|
||||
peer, so we don't need to call socket_ip_address here. */
|
||||
|
||||
/* Form the request. */
|
||||
/* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
|
||||
request = ftp_request ("EPSV", (sa->sa_family == AF_INET ? "1" : "2"));
|
||||
request = ftp_request ("EPSV", (ip->type == IPV4_ADDRESS ? "1" : "2"));
|
||||
|
||||
/* And send it. */
|
||||
nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
|
||||
|
65
src/ftp.c
65
src/ftp.c
@ -123,22 +123,6 @@ ftp_expected_bytes (const char *s)
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
static int
|
||||
getfamily (int fd)
|
||||
{
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr *sa = (struct sockaddr *)&ss;
|
||||
socklen_t len = sizeof (ss);
|
||||
|
||||
assert (fd >= 0);
|
||||
|
||||
if (getpeername (fd, sa, &len) < 0)
|
||||
/* Mauro Tortonesi: HOW DO WE HANDLE THIS ERROR? */
|
||||
abort ();
|
||||
|
||||
return sa->sa_family;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function sets up a passive data connection with the FTP server.
|
||||
* It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv.
|
||||
@ -147,16 +131,24 @@ static uerr_t
|
||||
ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, int *port)
|
||||
{
|
||||
uerr_t err;
|
||||
int family;
|
||||
|
||||
family = getfamily (rbuf->fd);
|
||||
assert (family == AF_INET || family == AF_INET6);
|
||||
/* We need to determine the address family and need to call
|
||||
getpeername, so while we're at it, store the address to ADDR.
|
||||
ftp_pasv and ftp_lpsv can simply override it. */
|
||||
if (!socket_ip_address (RBUF_FD (rbuf), addr, ENDPOINT_PEER))
|
||||
abort ();
|
||||
|
||||
/* If our control connection is over IPv6, then we first try EPSV and then
|
||||
* LPSV if the former is not supported. If the control connection is over
|
||||
* IPv4, we simply issue the good old PASV request. */
|
||||
if (family == AF_INET6)
|
||||
switch (addr->type)
|
||||
{
|
||||
case IPV4_ADDRESS:
|
||||
if (!opt.server_response)
|
||||
logputs (LOG_VERBOSE, "==> PASV ... ");
|
||||
err = ftp_pasv (rbuf, addr, port);
|
||||
break;
|
||||
case IPV6_ADDRESS:
|
||||
if (!opt.server_response)
|
||||
logputs (LOG_VERBOSE, "==> EPSV ... ");
|
||||
err = ftp_epsv (rbuf, addr, port);
|
||||
@ -168,12 +160,9 @@ ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, int *port)
|
||||
logputs (LOG_VERBOSE, "==> LPSV ... ");
|
||||
err = ftp_lpsv (rbuf, addr, port);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!opt.server_response)
|
||||
logputs (LOG_VERBOSE, "==> PASV ... ");
|
||||
err = ftp_pasv (rbuf, addr, port);
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
return err;
|
||||
@ -187,19 +176,25 @@ static uerr_t
|
||||
ftp_do_port (struct rbuf *rbuf, int *local_sock)
|
||||
{
|
||||
uerr_t err;
|
||||
int family;
|
||||
ip_address cip;
|
||||
|
||||
assert (rbuf != NULL);
|
||||
assert (rbuf_initialized_p (rbuf));
|
||||
|
||||
family = getfamily (rbuf->fd);
|
||||
assert (family == AF_INET || family == AF_INET6);
|
||||
if (!socket_ip_address (RBUF_FD (rbuf), &cip, ENDPOINT_PEER))
|
||||
abort ();
|
||||
|
||||
/* If our control connection is over IPv6, then we first try EPRT and then
|
||||
* LPRT if the former is not supported. If the control connection is over
|
||||
* IPv4, we simply issue the good old PORT request. */
|
||||
if (family == AF_INET6)
|
||||
switch (cip.type)
|
||||
{
|
||||
case IPV4_ADDRESS:
|
||||
if (!opt.server_response)
|
||||
logputs (LOG_VERBOSE, "==> PORT ... ");
|
||||
err = ftp_port (rbuf, local_sock);
|
||||
break;
|
||||
case IPV6_ADDRESS:
|
||||
if (!opt.server_response)
|
||||
logputs (LOG_VERBOSE, "==> EPRT ... ");
|
||||
err = ftp_eprt (rbuf, local_sock);
|
||||
@ -211,14 +206,10 @@ ftp_do_port (struct rbuf *rbuf, int *local_sock)
|
||||
logputs (LOG_VERBOSE, "==> LPRT ... ");
|
||||
err = ftp_lprt (rbuf, local_sock);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!opt.server_response)
|
||||
logputs (LOG_VERBOSE, "==> PORT ... ");
|
||||
err = ftp_port (rbuf, local_sock);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
|
77
src/host.c
77
src/host.c
@ -124,61 +124,44 @@ address_list_address_at (const struct address_list *al, int pos)
|
||||
return al->addresses + pos;
|
||||
}
|
||||
|
||||
/* Check whether two address lists have all their IPs in common. */
|
||||
/* Return 1 if IP is one of the addresses in AL. */
|
||||
|
||||
int
|
||||
address_list_match_all (const struct address_list *al1,
|
||||
const struct address_list *al2)
|
||||
address_list_find (const struct address_list *al, const ip_address *ip)
|
||||
{
|
||||
#ifdef ENABLE_IPV6
|
||||
int i;
|
||||
#endif
|
||||
if (al1 == al2)
|
||||
return 1;
|
||||
if (al1->count != al2->count)
|
||||
return 0;
|
||||
|
||||
/* For the comparison to be complete, we'd need to sort the IP
|
||||
addresses first. But that's not necessary because this is only
|
||||
used as an optimization. */
|
||||
|
||||
#ifndef ENABLE_IPV6
|
||||
/* In the non-IPv6 case, there is only one address type, so we can
|
||||
compare the whole array with memcmp. */
|
||||
return 0 == memcmp (al1->addresses, al2->addresses,
|
||||
al1->count * sizeof (ip_address));
|
||||
#else /* ENABLE_IPV6 */
|
||||
for (i = 0; i < al1->count; ++i)
|
||||
switch (ip->type)
|
||||
{
|
||||
const ip_address *ip1 = &al1->addresses[i];
|
||||
const ip_address *ip2 = &al2->addresses[i];
|
||||
|
||||
if (ip1->type != ip2->type)
|
||||
return 0;
|
||||
|
||||
switch (ip1->type)
|
||||
case IPV4_ADDRESS:
|
||||
for (i = 0; i < al->count; i++)
|
||||
{
|
||||
case IPV4_ADDRESS:
|
||||
if (ADDRESS_IPV4_IN_ADDR (ip1).s_addr
|
||||
!=
|
||||
ADDRESS_IPV4_IN_ADDR (ip2).s_addr)
|
||||
return 0;
|
||||
break;
|
||||
case IPV6_ADDRESS:
|
||||
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
|
||||
if (ADDRESS_IPV6_SCOPE (ip1) != ADDRESS_IPV6_SCOPE (ip2))
|
||||
return 0;
|
||||
#endif /* HAVE_SOCKADDR_IN6_SCOPE_ID */
|
||||
if (!IN6_ARE_ADDR_EQUAL (&ADDRESS_IPV6_IN6_ADDR (ip1),
|
||||
&ADDRESS_IPV6_IN6_ADDR (ip2)))
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
ip_address *cur = al->addresses + i;
|
||||
if (cur->type == IPV4_ADDRESS
|
||||
&& (ADDRESS_IPV4_IN_ADDR (cur).s_addr
|
||||
==
|
||||
ADDRESS_IPV4_IN_ADDR (ip).s_addr))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
#ifdef ENABLE_IPV6
|
||||
case IPV6_ADDRESS:
|
||||
for (i = 0; i < al->count; i++)
|
||||
{
|
||||
ip_address *cur = al->addresses + i;
|
||||
if (cur->type == IPV6_ADDRESS
|
||||
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
|
||||
&& ADDRESS_IPV6_SCOPE (cur) == ADDRESS_IPV6_SCOPE (ip)
|
||||
#endif
|
||||
&& IN6_ARE_ADDR_EQUAL (&ADDRESS_IPV6_IN6_ADDR (cur),
|
||||
&ADDRESS_IPV6_IN6_ADDR (ip)))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
default:
|
||||
abort ();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark the INDEXth element of AL as faulty, so that the next time
|
||||
|
@ -108,8 +108,7 @@ void address_list_get_bounds PARAMS ((const struct address_list *,
|
||||
int address_list_cached_p PARAMS ((const struct address_list *));
|
||||
const ip_address *address_list_address_at PARAMS ((const struct address_list *,
|
||||
int));
|
||||
int address_list_match_all PARAMS ((const struct address_list *,
|
||||
const struct address_list *));
|
||||
int address_list_find PARAMS ((const struct address_list *, const ip_address *));
|
||||
void address_list_set_faulty PARAMS ((struct address_list *, int));
|
||||
void address_list_release PARAMS ((struct address_list *));
|
||||
|
||||
|
184
src/http.c
184
src/http.c
@ -343,40 +343,36 @@ http_process_set_cookie (const char *hdr, void *arg)
|
||||
/* Persistent connections. Currently, we cache the most recently used
|
||||
connection as persistent, provided that the HTTP server agrees to
|
||||
make it such. The persistence data is stored in the variables
|
||||
below. Ideally, it would be in a structure, and it should be
|
||||
possible to cache an arbitrary fixed number of these connections.
|
||||
|
||||
I think the code is quite easy to extend in that direction. */
|
||||
below. Ideally, it should be possible to cache an arbitrary fixed
|
||||
number of these connections. */
|
||||
|
||||
/* Whether a persistent connection is active. */
|
||||
static int pc_active_p;
|
||||
static int pconn_active;
|
||||
|
||||
/* Host and port of currently active persistent connection. */
|
||||
static struct address_list *pc_last_host_ip;
|
||||
static unsigned short pc_last_port;
|
||||
static struct {
|
||||
/* The socket of the connection. */
|
||||
int socket;
|
||||
|
||||
/* File descriptor of the currently active persistent connection. */
|
||||
static int pc_last_fd;
|
||||
/* Host and port of the currently active persistent connection. */
|
||||
char *host;
|
||||
int port;
|
||||
|
||||
/* Whether a ssl handshake has occoured on this connection */
|
||||
static int pc_last_ssl_p;
|
||||
/* Whether a ssl handshake has occoured on this connection. */
|
||||
int ssl;
|
||||
} pconn;
|
||||
|
||||
/* Mark the persistent connection as invalid. This is used by the
|
||||
CLOSE_* macros after they forcefully close a registered persistent
|
||||
connection. This does not close the file descriptor -- it is left
|
||||
to the caller to do that. (Maybe it should, though.) */
|
||||
/* Mark the persistent connection as invalid and free the resources it
|
||||
uses. This is used by the CLOSE_* macros after they forcefully
|
||||
close a registered persistent connection. */
|
||||
|
||||
static void
|
||||
invalidate_persistent (void)
|
||||
{
|
||||
pc_active_p = 0;
|
||||
pc_last_ssl_p = 0;
|
||||
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 (("Disabling further reuse of socket %d.\n", pconn.socket));
|
||||
pconn_active = 0;
|
||||
xclose (pconn.socket);
|
||||
xfree (pconn.host);
|
||||
xzero (pconn);
|
||||
}
|
||||
|
||||
/* Register FD, which should be a TCP/IP connection to HOST:PORT, as
|
||||
@ -388,94 +384,108 @@ invalidate_persistent (void)
|
||||
If a previous connection was persistent, it is closed. */
|
||||
|
||||
static void
|
||||
register_persistent (const char *host, unsigned short port, int fd, int ssl)
|
||||
register_persistent (const char *host, int port, int fd, int ssl)
|
||||
{
|
||||
if (pc_active_p)
|
||||
if (pconn_active)
|
||||
{
|
||||
if (pc_last_fd == fd)
|
||||
if (pconn.socket == fd)
|
||||
{
|
||||
/* The connection FD is already registered. Nothing to
|
||||
do. */
|
||||
/* The connection FD is already registered. */
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The old persistent connection is still active; let's
|
||||
close it first. This situation arises whenever a
|
||||
persistent connection exists, but we then connect to a
|
||||
different host, and try to register a persistent
|
||||
connection to that one. */
|
||||
xclose (pc_last_fd);
|
||||
/* The old persistent connection is still active; close it
|
||||
first. This situation arises whenever a persistent
|
||||
connection exists, but we then connect to a different
|
||||
host, and try to register a persistent connection to that
|
||||
one. */
|
||||
invalidate_persistent ();
|
||||
}
|
||||
}
|
||||
|
||||
assert (pc_last_host_ip == NULL);
|
||||
pconn_active = 1;
|
||||
pconn.socket = fd;
|
||||
pconn.host = xstrdup (host);
|
||||
pconn.port = port;
|
||||
pconn.ssl = ssl;
|
||||
|
||||
/* This lookup_host cannot fail, because it has the results in the
|
||||
cache. */
|
||||
pc_last_host_ip = lookup_host (host, LH_SILENT);
|
||||
assert (pc_last_host_ip != NULL);
|
||||
|
||||
pc_last_port = port;
|
||||
pc_last_fd = fd;
|
||||
pc_active_p = 1;
|
||||
pc_last_ssl_p = ssl;
|
||||
DEBUGP (("Registered fd %d for persistent reuse.\n", fd));
|
||||
DEBUGP (("Registered socket %d for persistent reuse.\n", fd));
|
||||
}
|
||||
|
||||
/* Return non-zero if a persistent connection is available for
|
||||
connecting to HOST:PORT. */
|
||||
|
||||
static int
|
||||
persistent_available_p (const char *host, unsigned short port, int ssl)
|
||||
persistent_available_p (const char *host, int port, int ssl,
|
||||
int *host_lookup_failed)
|
||||
{
|
||||
int success;
|
||||
struct address_list *this_host_ip;
|
||||
|
||||
/* First, check whether a persistent connection is active at all. */
|
||||
if (!pc_active_p)
|
||||
return 0;
|
||||
/* Second, check if the active connection pertains to the correct
|
||||
(HOST, PORT) ordered pair. */
|
||||
if (port != pc_last_port)
|
||||
if (!pconn_active)
|
||||
return 0;
|
||||
|
||||
/* Second, a): check if current connection is (not) ssl, too. This
|
||||
test is unlikely to fail because HTTP and HTTPS typicaly use
|
||||
different ports. Yet it is possible, or so I [Christian
|
||||
Fraenkel] have been told, to run HTTPS and HTTP simultaneus on
|
||||
the same port. */
|
||||
if (ssl != pc_last_ssl_p)
|
||||
/* If we want SSL and the last connection wasn't or vice versa,
|
||||
don't use it. Checking for host and port is not enough because
|
||||
HTTP and HTTPS can apparently coexist on the same port. */
|
||||
if (ssl != pconn.ssl)
|
||||
return 0;
|
||||
|
||||
this_host_ip = lookup_host (host, 0);
|
||||
if (!this_host_ip)
|
||||
/* If we're not connecting to the same port, we're not interested. */
|
||||
if (port != pconn.port)
|
||||
return 0;
|
||||
|
||||
/* 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;
|
||||
/* If the host is the same, we're in business. If not, there is
|
||||
still hope -- read below. */
|
||||
if (0 != strcasecmp (host, pconn.host))
|
||||
{
|
||||
/* This is somewhat evil, but works in practice: if the address
|
||||
that pconn.socket is connected to is one of the IP addresses
|
||||
HOST resolves to, we don't need to reconnect. #### Is it
|
||||
correct to do this by default? */
|
||||
int found;
|
||||
ip_address ip;
|
||||
struct address_list *al;
|
||||
|
||||
/* Third: check whether the connection is still open. This is
|
||||
if (!socket_ip_address (pconn.socket, &ip, 0))
|
||||
{
|
||||
/* Can't get the peer's address -- something must be wrong
|
||||
with the connection. */
|
||||
invalidate_persistent ();
|
||||
return 0;
|
||||
}
|
||||
al = lookup_host (host, 0);
|
||||
if (!al)
|
||||
{
|
||||
*host_lookup_failed = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
found = address_list_find (al, &ip);
|
||||
address_list_release (al);
|
||||
|
||||
if (!found)
|
||||
return 0;
|
||||
|
||||
/* HOST resolves to an address pconn.sock is connected to -- no
|
||||
need to reconnect. */
|
||||
}
|
||||
|
||||
/* Finally, check whether the connection is still open. This is
|
||||
important because most server implement a liberal (short) timeout
|
||||
on persistent connections. Wget can of course always reconnect
|
||||
if the connection doesn't work out, but it's nicer to know in
|
||||
advance. This test is a logical followup of the first test, but
|
||||
is "expensive" and therefore placed at the end of the list. */
|
||||
if (!test_socket_open (pc_last_fd))
|
||||
|
||||
if (!test_socket_open (pconn.socket))
|
||||
{
|
||||
/* Oops, the socket is no longer open. Now that we know that,
|
||||
let's invalidate the persistent connection before returning
|
||||
0. */
|
||||
xclose (pc_last_fd);
|
||||
invalidate_persistent ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -497,16 +507,18 @@ persistent_available_p (const char *host, unsigned short port, int ssl)
|
||||
#define CLOSE_FINISH(fd) do { \
|
||||
if (!keep_alive) \
|
||||
{ \
|
||||
xclose (fd); \
|
||||
if (pc_active_p && (fd) == pc_last_fd) \
|
||||
if (pconn_active && (fd) == pconn.socket) \
|
||||
invalidate_persistent (); \
|
||||
else \
|
||||
xclose (fd); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CLOSE_INVALIDATE(fd) do { \
|
||||
xclose (fd); \
|
||||
if (pc_active_p && (fd) == pc_last_fd) \
|
||||
if (pconn_active && (fd) == pconn.socket) \
|
||||
invalidate_persistent (); \
|
||||
else \
|
||||
xclose (fd); \
|
||||
} while (0)
|
||||
|
||||
struct http_stat
|
||||
@ -606,6 +618,8 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
||||
char *post_content_type, *post_content_length;
|
||||
long post_data_size = 0;
|
||||
|
||||
int host_lookup_failed;
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
/* Initialize the SSL context. After the first run, this is a
|
||||
no-op. */
|
||||
@ -668,6 +682,8 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
||||
server. */
|
||||
conn = proxy ? proxy : u;
|
||||
|
||||
host_lookup_failed = 0;
|
||||
|
||||
/* First: establish the connection. */
|
||||
if (inhibit_keep_alive
|
||||
|| !persistent_available_p (conn->host, conn->port,
|
||||
@ -676,8 +692,14 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
))
|
||||
, &host_lookup_failed))
|
||||
{
|
||||
/* In its current implementation, persistent_available_p will
|
||||
look up conn->host in some cases. If that lookup failed, we
|
||||
don't need to bother with connect_to_host. */
|
||||
if (host_lookup_failed)
|
||||
return HOSTERR;
|
||||
|
||||
sock = connect_to_host (conn->host, conn->port);
|
||||
if (sock == E_HOST)
|
||||
return HOSTERR;
|
||||
@ -705,8 +727,8 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
||||
conn->host, conn->port);
|
||||
/* #### pc_last_fd should be accessed through an accessor
|
||||
function. */
|
||||
sock = pc_last_fd;
|
||||
using_ssl = pc_last_ssl_p;
|
||||
sock = pconn.socket;
|
||||
using_ssl = pconn.ssl;
|
||||
DEBUGP (("Reusing fd %d.\n", sock));
|
||||
}
|
||||
|
||||
@ -2427,6 +2449,4 @@ create_authorization_line (const char *au, const char *user,
|
||||
void
|
||||
http_cleanup (void)
|
||||
{
|
||||
if (pc_last_host_ip)
|
||||
address_list_release (pc_last_host_ip);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user