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

[svn] Networking improvements: get rid of the MSOCK global variable,

move the sockaddr handling to connect.c, make sure Wget refreshes
the DNS lookup after it becomes stale.
This commit is contained in:
hniksic 2003-10-30 16:18:08 -08:00
parent e4ff71fca5
commit add61a2d9c
10 changed files with 428 additions and 465 deletions

View File

@ -1,3 +1,36 @@
2003-10-31 Hrvoje Niksic <hniksic@xemacs.org>
* sysdep.h (CLOSE): Don't call close on file descriptors less than
0, i.e. on uncreated sockets.
* connect.c (resolve_bind_address): Work on struct sockaddr
directly.
(connect_to_host): Replacement for connect_to_many. Resolve HOST
and connect to any of its addresses. If we can't connect and the
host name lookup was cached, try to resolve it again. This should
fix problems with hosts behind dynamic DNS. Updated all callers.
(connect_to_ip): Replacement for connect_to_one. Removed SILENT;
added the argument PRINT instead. Updated all callers.
(set_connection_host_name): Removed.
* host.c (address_list_address_at): New function instead of
address_list_copy_one. It returns a pointer to ip_address *, so
it's not necessary to copy the data.
(address_list_cached_p): New function.
(forget_host_lookup): Ditto.
* connect.c: Got rid of the MSOCK global variable. Made bindport
return the local socket it creates. Added a new argument to
acceptport, the socket to call accept on. Updated callers.
(closeport): Removed.
* connect.c: Moved the sockaddr code from host.c to this file,
because most of that stuff is used for connecting, and has nothing
to do with host names anyway.
(sockaddr_set_data, sockaddr_get_data): New functions, replace the
old sockaddr_set_address, sockaddr_set_port, sockaddr_get_address,
and sockaddr_get_port.
2003-10-30 Hrvoje Niksic <hniksic@xemacs.org> 2003-10-30 Hrvoje Niksic <hniksic@xemacs.org>
* sysdep.h: Use `S >= 8' rather than `S == 8' when looking for * sysdep.h: Use `S >= 8' rather than `S == 8' when looking for

View File

@ -6,7 +6,7 @@ This file is part of GNU Wget.
GNU Wget is free software; you can redistribute it and/or modify GNU Wget is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
GNU Wget is distributed in the hope that it will be useful, GNU Wget is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
@ -65,48 +65,143 @@ so, delete this exception statement from your version. */
extern int errno; extern int errno;
#endif #endif
/* Variables shared by bindport and acceptport: */
static int msock = -1; /**
/*static struct sockaddr *addr;*/ * sockaddr_set_data
*
static int * This function takes a sockaddr struct and fills in the protocol
resolve_bind_address (int flags, ip_address *addr) * type, the port number and the address. If ENABLE_IPV6 is defined,
* SA should really point to struct sockaddr_storage; otherwise, it
* should point to struct sockaddr_in.
*
* Input:
* struct sockaddr* The space to be filled
* const ip_address The IP address
* int The port
*
* Return:
* - Only modifies 1st parameter.
*/
static void
sockaddr_set_data (struct sockaddr *sa, const ip_address *addr, int port)
{ {
struct address_list *al = NULL; if (addr->type == IPV4_ADDRESS)
int resolved = 0;
if (opt.bind_address != NULL)
{ {
al = lookup_host (opt.bind_address, flags | LH_SILENT | LH_PASSIVE); struct sockaddr_in *sin = (struct sockaddr_in *)sa;
sin->sin_family = AF_INET;
sin->sin_port = htons (port);
if (addr == NULL)
sin->sin_addr.s_addr = INADDR_ANY;
else
sin->sin_addr = ADDRESS_IPV4_IN_ADDR (addr);
}
#ifdef ENABLE_IPV6
else if (addr->type == IPV6_ADDRESS)
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons (port);
/* #### How can ADDR be NULL? We have dereferenced it above by
accessing addr->type! */
if (addr == NULL)
{
sin6->sin6_addr = in6addr_any;
/* #### Should we set the scope_id here? */
}
else
{
sin6->sin6_addr = ADDRESS_IPV6_IN6_ADDR (addr);
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
sin6->sin6_scope_id = ADDRESS_IPV6_SCOPE (addr);
#endif
}
}
#endif /* ENABLE_IPV6 */
else
abort ();
}
/* Get the data of SA, specifically the IP address and the port. If
you're not interested in one or the other information, pass NULL as
the pointer. */
void
sockaddr_get_data (const struct sockaddr *sa, ip_address *ip, int *port)
{
if (sa->sa_family == AF_INET)
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
if (ip)
{
ip->type = IPV4_ADDRESS;
ADDRESS_IPV4_IN_ADDR (ip) = sin->sin_addr;
}
if (port)
*port = ntohs (sin->sin_port);
}
#ifdef ENABLE_IPV6
else if (sa->sa_family == AF_INET6)
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
if (ip)
{
ip->type = IPV6_ADDRESS;
ADDRESS_IPV6_IN6_ADDR (ip) = sin6->sin6_addr;
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
ADDRESS_IPV6_SCOPE (ip) = sin6->sin6_scope_id;
#endif
}
if (port)
*port = ntohs (sin6->sin6_port);
}
#endif
else
abort ();
}
/* Return the size of the sockaddr structure depending on its
family. */
static socklen_t
sockaddr_size (const struct sockaddr *sa)
{
switch (sa->sa_family)
{
case AF_INET:
return sizeof (struct sockaddr_in);
#ifdef ENABLE_IPV6
case AF_INET6:
return sizeof (struct sockaddr_in6);
#endif
default:
abort ();
return 0; /* so the compiler shuts up. */
}
}
static int
resolve_bind_address (const char *host, struct sockaddr *sa, int flags)
{
struct address_list *al;
/* #### Shouldn't we do this only once? opt.bind_address won't
change during a Wget run! */
al = lookup_host (host, flags | LH_SILENT | LH_PASSIVE);
if (al == NULL) if (al == NULL)
{ {
logprintf (LOG_NOTQUIET, logprintf (LOG_NOTQUIET,
_("Unable to convert `%s' to a bind address. Reverting to ANY.\n"), _("Unable to convert `%s' to a bind address. Reverting to ANY.\n"),
opt.bind_address); opt.bind_address);
} return 0;
else
resolved = 1;
} }
if (al == NULL) /* Pick the first address in the list and use it as bind address.
{ Perhaps we should try multiple addresses, but I don't think
/* #### Is there really a need for this? Shouldn't we simply that's necessary in practice. */
return 0 and have the caller use sockaddr_set_address to sockaddr_set_data (sa, address_list_address_at (al, 0), 0);
specify INADDR_ANY/in6addr_any? */
const char *unspecified_address = "0.0.0.0";
#ifdef ENABLE_IPV6
if (flags & BIND_ON_IPV6_ONLY)
unspecified_address = "::";
#endif
al = lookup_host (unspecified_address, LH_SILENT | LH_PASSIVE);
}
assert (al != NULL);
address_list_copy_one (al, 0, addr);
address_list_release (al); address_list_release (al);
return 1;
return resolved;
} }
struct cwt_context { struct cwt_context {
@ -146,76 +241,61 @@ connect_with_timeout (int fd, const struct sockaddr *addr, socklen_t addrlen,
return ctx.result; return ctx.result;
} }
/* A kludge, but still better than passing the host name all the way /* Connect to a remote endpoint whose IP address is known. */
to connect_to_one. */
static const char *connection_host_name;
void
set_connection_host_name (const char *host)
{
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. */
int int
connect_to_one (ip_address *addr, unsigned short port, int silent) connect_to_ip (const ip_address *ip, int port, const char *print)
{ {
struct sockaddr_storage ss; struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr *)&ss; struct sockaddr *sa = (struct sockaddr *)&ss;
int sock, save_errno; int sock, save_errno;
/* Set port and protocol */ /* If PRINT is non-NULL, print the "Connecting to..." line, with
sockaddr_set_address (sa, port, addr); PRINT being the host name we're connecting to. */
if (print)
if (!silent)
{ {
const char *pretty_addr = pretty_print_address (addr); const char *txt_addr = pretty_print_address (ip);
if (connection_host_name if (print && 0 != strcmp (print, txt_addr))
&& 0 != strcmp (connection_host_name, pretty_addr)) logprintf (LOG_VERBOSE,
logprintf (LOG_VERBOSE, _("Connecting to %s[%s]:%hu... "), _("Connecting to %s{%s}:%d... "), print, txt_addr, port);
connection_host_name, pretty_addr, port);
else else
logprintf (LOG_VERBOSE, _("Connecting to %s:%hu... "), logprintf (LOG_VERBOSE, _("Connecting to %s:%d... "), txt_addr, port);
pretty_addr, port);
} }
/* Store the sockaddr info to SA. */
sockaddr_set_data (sa, ip, port);
/* Create the socket of the family appropriate for the address. */ /* Create the socket of the family appropriate for the address. */
sock = socket (sa->sa_family, SOCK_STREAM, 0); sock = socket (sa->sa_family, SOCK_STREAM, 0);
if (sock < 0) if (sock < 0)
goto out; goto out;
/* For very small rate limits, set the buffer size (and hence, /* For very small rate limits, set the buffer size (and hence,
hopefully, the size of the kernel window) to the size of the hopefully, the kernel's TCP window size) to the per-second limit.
limit. That way we don't sleep for more than 1s between network That way we should never have to sleep for more than 1s between
reads. */ network reads. */
if (opt.limit_rate && opt.limit_rate < 8192) if (opt.limit_rate && opt.limit_rate < 8192)
{ {
int bufsize = opt.limit_rate; int bufsize = opt.limit_rate;
if (bufsize < 512) if (bufsize < 512)
bufsize = 512; bufsize = 512; /* avoid pathologically small values */
#ifdef SO_RCVBUF #ifdef SO_RCVBUF
setsockopt (sock, SOL_SOCKET, SO_RCVBUF, setsockopt (sock, SOL_SOCKET, SO_RCVBUF,
(char *)&bufsize, sizeof (bufsize)); (void *)&bufsize, (socklen_t)sizeof (bufsize));
#endif #endif
/* When we add opt.limit_rate support for writing, as with /* When we add limit_rate support for writing, which is useful
`--post-file', also set SO_SNDBUF here. */ for POST, we should also set SO_SNDBUF here. */
} }
if (opt.bind_address) if (opt.bind_address)
{ {
/* Bind the client side to the requested address. */ /* Bind the client side of the socket to the requested
ip_address bind_address; address. */
if (resolve_bind_address (0, &bind_address)) struct sockaddr_storage bind_ss;
struct sockaddr *bind_sa = (struct sockaddr *)&bind_ss;
if (resolve_bind_address (opt.bind_address, bind_sa, 0))
{ {
struct sockaddr_storage bss; if (bind (sock, bind_sa, sockaddr_size (bind_sa)) < 0)
struct sockaddr *bsa = (struct sockaddr *)&bss;
sockaddr_set_address (bsa, 0, &bind_address);
if (bind (sock, bsa, sockaddr_len (bsa)))
{ {
CLOSE (sock); CLOSE (sock);
sock = -1; sock = -1;
@ -224,8 +304,8 @@ connect_to_one (ip_address *addr, unsigned short port, int silent)
} }
} }
/* Connect the socket to the remote host. */ /* Connect the socket to the remote endpoint. */
if (connect_with_timeout (sock, sa, sockaddr_len (sa), if (connect_with_timeout (sock, sa, sockaddr_size (sa),
opt.connect_timeout) < 0) opt.connect_timeout) < 0)
{ {
CLOSE (sock); CLOSE (sock);
@ -237,14 +317,14 @@ connect_to_one (ip_address *addr, unsigned short port, int silent)
if (sock >= 0) if (sock >= 0)
{ {
/* Success. */ /* Success. */
if (!silent) if (print)
logprintf (LOG_VERBOSE, _("connected.\n")); logprintf (LOG_VERBOSE, _("connected.\n"));
DEBUGP (("Created socket %d.\n", sock)); DEBUGP (("Created socket %d.\n", sock));
} }
else else
{ {
save_errno = errno; save_errno = errno;
if (!silent) if (print)
logprintf (LOG_VERBOSE, "failed: %s.\n", strerror (errno)); logprintf (LOG_VERBOSE, "failed: %s.\n", strerror (errno));
errno = save_errno; errno = save_errno;
} }
@ -252,31 +332,47 @@ connect_to_one (ip_address *addr, unsigned short port, int silent)
return sock; return sock;
} }
/* Connect to a remote host whose address has been resolved. */ /* Connect to a remote endpoint specified by host name. */
int int
connect_to_many (struct address_list *al, unsigned short port, int silent) connect_to_host (const char *host, int port)
{ {
int i, start, end; int i, start, end;
struct address_list *al;
int sock = -1;
again:
al = lookup_host (host, 0);
if (!al)
return E_HOST;
address_list_get_bounds (al, &start, &end); address_list_get_bounds (al, &start, &end);
for (i = start; i < end; i++) for (i = start; i < end; i++)
{ {
ip_address addr; const ip_address *ip = address_list_address_at (al, i);
int sock; sock = connect_to_ip (ip, port, host);
address_list_copy_one (al, i, &addr);
sock = connect_to_one (&addr, port, silent);
if (sock >= 0) if (sock >= 0)
/* Success. */ /* Success. */
return sock; break;
address_list_set_faulty (al, i); address_list_set_faulty (al, i);
/* The attempt to connect has failed. Continue with the loop /* The attempt to connect has failed. Continue with the loop
and try next address. */ and try next address. */
} }
address_list_release (al);
return -1; if (sock < 0 && address_list_cached_p (al))
{
/* We were unable to connect to any address in a list we've
obtained from cache. There is a possibility that the host is
under dynamic DNS and has changed its address. Resolve it
again. */
forget_host_lookup (host);
goto again;
}
return sock;
} }
int int
@ -310,24 +406,20 @@ test_socket_open (int sock)
#endif #endif
} }
/* Bind the local port PORT. This does all the necessary work, which /* Create a socket and bind it to PORT locally. Calling accept() on
is creating a socket, setting SO_REUSEADDR option on it, then such a socket waits for and accepts incoming TCP connections. The
calling bind() and listen(). If *PORT is 0, a random port is resulting socket is stored to LOCAL_SOCK. */
chosen by the system, and its value is stored to *PORT. The
internal variable MPORT is set to the value of the ensuing master
socket. Call acceptport() to block for and accept a connection. */
uerr_t uerr_t
bindport (const ip_address *bind_address, unsigned short *port) bindport (const ip_address *bind_address, int *port, int *local_sock)
{ {
int msock;
int family = AF_INET; int family = AF_INET;
int optval; int optval;
struct sockaddr_storage ss; struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr *)&ss; struct sockaddr *sa = (struct sockaddr *)&ss;
memset (&ss, 0, sizeof (ss)); memset (&ss, 0, sizeof (ss));
msock = -1;
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
if (bind_address->type == IPV6_ADDRESS) if (bind_address->type == IPV6_ADDRESS)
family = AF_INET6; family = AF_INET6;
@ -339,8 +431,11 @@ bindport (const ip_address *bind_address, unsigned short *port)
#ifdef SO_REUSEADDR #ifdef SO_REUSEADDR
optval = 1; optval = 1;
if (setsockopt (msock, SOL_SOCKET, SO_REUSEADDR, if (setsockopt (msock, SOL_SOCKET, SO_REUSEADDR,
(char *)&optval, sizeof (optval)) < 0) (void *)&optval, (socklen_t)sizeof (optval)) < 0)
{
CLOSE (msock);
return CONSOCKERR; return CONSOCKERR;
}
#endif #endif
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
@ -350,38 +445,36 @@ bindport (const ip_address *bind_address, unsigned short *port)
optval = 1; optval = 1;
/* if setsockopt fails, go on anyway */ /* if setsockopt fails, go on anyway */
setsockopt (msock, IPPROTO_IPV6, IPV6_V6ONLY, setsockopt (msock, IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&optval, sizeof (optval)); (void *)&optval, (socklen_t)sizeof (optval));
} }
# endif # endif
#endif #endif
sockaddr_set_address (sa, htons (*port), bind_address); sockaddr_set_data (sa, bind_address, *port);
if (bind (msock, sa, sockaddr_len (sa)) < 0) if (bind (msock, sa, sockaddr_size (sa)) < 0)
{ {
CLOSE (msock); CLOSE (msock);
msock = -1;
return BINDERR; return BINDERR;
} }
DEBUGP (("Master socket fd %d bound.\n", msock)); DEBUGP (("Local socket fd %d bound.\n", msock));
if (!*port) if (!*port)
{ {
socklen_t sa_len = sockaddr_len (sa); socklen_t sa_len = sockaddr_size (sa);
if (getsockname (msock, sa, &sa_len) < 0) if (getsockname (msock, sa, &sa_len) < 0)
{ {
CLOSE (msock); CLOSE (msock);
msock = -1;
return CONPORTERR; return CONPORTERR;
} }
*port = sockaddr_get_port (sa); sockaddr_get_data (sa, NULL, port);
DEBUGP (("binding to address %s using port %i.\n", DEBUGP (("binding to address %s using port %i.\n",
pretty_print_address (bind_address), *port)); pretty_print_address (bind_address), *port));
} }
if (listen (msock, 1) < 0) if (listen (msock, 1) < 0)
{ {
CLOSE (msock); CLOSE (msock);
msock = -1;
return LISTENERR; return LISTENERR;
} }
*local_sock = msock;
return BINDOK; return BINDOK;
} }
@ -420,41 +513,28 @@ select_fd (int fd, double maxtime, int writep)
} }
#endif /* HAVE_SELECT */ #endif /* HAVE_SELECT */
/* Call accept() on MSOCK and store the result to *SOCK. This assumes /* Accept a connection on LOCAL_SOCK, and store the new socket to
that bindport() has been used to initialize MSOCK to a correct *SOCK. It blocks the caller until a connection is established. If
value. It blocks the caller until a connection is established. If no connection is established for opt.connect_timeout seconds, the
no connection is established for OPT.CONNECT_TIMEOUT seconds, the
function exits with an error status. */ function exits with an error status. */
uerr_t uerr_t
acceptport (int *sock) acceptport (int local_sock, int *sock)
{ {
struct sockaddr_storage ss; struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr *)&ss; struct sockaddr *sa = (struct sockaddr *)&ss;
socklen_t addrlen = sizeof (ss); socklen_t addrlen = sizeof (ss);
#ifdef HAVE_SELECT #ifdef HAVE_SELECT
if (select_fd (msock, opt.connect_timeout, 0) <= 0) if (select_fd (local_sock, opt.connect_timeout, 0) <= 0)
return ACCEPTERR; return ACCEPTERR;
#endif #endif
if ((*sock = accept (msock, sa, &addrlen)) < 0) if ((*sock = accept (local_sock, sa, &addrlen)) < 0)
return ACCEPTERR; return ACCEPTERR;
DEBUGP (("Created socket fd %d.\n", *sock)); DEBUGP (("Created socket fd %d.\n", *sock));
return ACCEPTOK; return ACCEPTOK;
} }
/* Close SOCK, as well as the most recently remembered MSOCK, created
via bindport(). If SOCK is -1, close MSOCK only. */
void
closeport (int sock)
{
/*shutdown (sock, 2);*/
if (sock != -1)
CLOSE (sock);
if (msock != -1)
CLOSE (msock);
msock = -1;
}
/* Return the local IP address associated with the connection on FD. */ /* Return the local IP address associated with the connection on FD. */
int int

View File

@ -6,7 +6,7 @@ This file is part of GNU Wget.
GNU Wget is free software; you can redistribute it and/or modify GNU Wget is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
GNU Wget is distributed in the hope that it will be useful, GNU Wget is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
@ -32,21 +32,32 @@ so, delete this exception statement from your version. */
#include "host.h" /* for definition of ip_address */ #include "host.h" /* for definition of ip_address */
/* Returned by connect_to_host when host name cannot be resolved. */
enum {
E_HOST = -100
};
/* bindport flags */ /* bindport flags */
#define BIND_ON_IPV4_ONLY LH_IPV4_ONLY #define BIND_ON_IPV4_ONLY LH_IPV4_ONLY
#define BIND_ON_IPV6_ONLY LH_IPV6_ONLY #define BIND_ON_IPV6_ONLY LH_IPV6_ONLY
#ifndef ENABLE_IPV6
# ifndef HAVE_SOCKADDR_STORAGE
# define sockaddr_storage sockaddr_in
# endif
#endif /* ENABLE_IPV6 */
/* Function declarations */ /* Function declarations */
int connect_to_one PARAMS ((ip_address *, unsigned short, int)); int connect_to_ip PARAMS ((const ip_address *, int, const char *));
int connect_to_many PARAMS ((struct address_list *, unsigned short, int)); int connect_to_host PARAMS ((const char *, int));
void set_connection_host_name PARAMS ((const char *));
void sockaddr_get_data PARAMS ((const struct sockaddr *, ip_address *, int *));
int test_socket_open PARAMS ((int)); int test_socket_open PARAMS ((int));
int select_fd PARAMS ((int, double, int)); int select_fd PARAMS ((int, double, int));
uerr_t bindport PARAMS ((const ip_address *, unsigned short *)); uerr_t bindport PARAMS ((const ip_address *, int *, int *));
uerr_t acceptport PARAMS ((int *)); uerr_t acceptport PARAMS ((int, int *));
void closeport PARAMS ((int));
int conaddr PARAMS ((int, ip_address *)); int conaddr PARAMS ((int, ip_address *));
int iread PARAMS ((int, char *, int)); int iread PARAMS ((int, char *, int));

View File

@ -254,7 +254,7 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass)
} }
static void static void
ip_address_to_port_repr (const ip_address *addr, unsigned short port, char *buf, ip_address_to_port_repr (const ip_address *addr, int port, char *buf,
size_t buflen) size_t buflen)
{ {
unsigned char *ptr; unsigned char *ptr;
@ -267,7 +267,7 @@ ip_address_to_port_repr (const ip_address *addr, unsigned short port, char *buf,
ptr = ADDRESS_IPV4_DATA (addr); ptr = ADDRESS_IPV4_DATA (addr);
snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1], snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1],
ptr[2], ptr[3], (unsigned) (port & 0xff00) >> 8, port & 0xff); ptr[2], ptr[3], (port & 0xff00) >> 8, port & 0xff);
buf[buflen - 1] = '\0'; buf[buflen - 1] = '\0';
} }
@ -275,13 +275,13 @@ ip_address_to_port_repr (const ip_address *addr, unsigned short port, char *buf,
server. Use acceptport after RETR, to get the socket of data server. Use acceptport after RETR, to get the socket of data
connection. */ connection. */
uerr_t uerr_t
ftp_port (struct rbuf *rbuf) ftp_port (struct rbuf *rbuf, int *local_sock)
{ {
uerr_t err; uerr_t err;
char *request, *respline; char *request, *respline;
ip_address addr; ip_address addr;
int nwritten; int nwritten;
unsigned short port; int port;
/* Must contain the argument of PORT (of the form a,b,c,d,e,f). */ /* Must contain the argument of PORT (of the form a,b,c,d,e,f). */
char bytes[6 * 4 + 1]; char bytes[6 * 4 + 1];
@ -298,7 +298,7 @@ ftp_port (struct rbuf *rbuf)
port = 0; port = 0;
/* Bind the port. */ /* Bind the port. */
err = bindport (&addr, &port); err = bindport (&addr, &port, local_sock);
if (err != BINDOK) if (err != BINDOK)
return err; return err;
@ -311,7 +311,7 @@ ftp_port (struct rbuf *rbuf)
if (nwritten < 0) if (nwritten < 0)
{ {
xfree (request); xfree (request);
closeport (-1); CLOSE (*local_sock);
return WRITEFAILED; return WRITEFAILED;
} }
xfree (request); xfree (request);
@ -321,13 +321,13 @@ ftp_port (struct rbuf *rbuf)
if (err != FTPOK) if (err != FTPOK)
{ {
xfree (respline); xfree (respline);
closeport (-1); CLOSE (*local_sock);
return err; return err;
} }
if (*respline != '2') if (*respline != '2')
{ {
xfree (respline); xfree (respline);
closeport (-1); CLOSE (*local_sock);
return FTPPORTERR; return FTPPORTERR;
} }
xfree (respline); xfree (respline);
@ -336,7 +336,7 @@ ftp_port (struct rbuf *rbuf)
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
static void static void
ip_address_to_lprt_repr (const ip_address *addr, unsigned short port, char *buf, ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf,
size_t buflen) size_t buflen)
{ {
unsigned char *ptr; unsigned char *ptr;
@ -354,7 +354,7 @@ ip_address_to_lprt_repr (const ip_address *addr, unsigned short port, char *buf,
ptr = ADDRESS_IPV4_DATA (addr); ptr = ADDRESS_IPV4_DATA (addr);
snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4, snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4,
ptr[0], ptr[1], ptr[2], ptr[3], 2, ptr[0], ptr[1], ptr[2], ptr[3], 2,
(unsigned) (port & 0xff00) >> 8, port & 0xff); (port & 0xff00) >> 8, port & 0xff);
buf[buflen - 1] = '\0'; buf[buflen - 1] = '\0';
break; break;
case IPV6_ADDRESS: case IPV6_ADDRESS:
@ -362,7 +362,7 @@ ip_address_to_lprt_repr (const ip_address *addr, unsigned short port, char *buf,
snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
6, 16, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], 6, 16, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], 2, ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], 2,
(unsigned) (port & 0xff00) >> 8, port & 0xff); (port & 0xff00) >> 8, port & 0xff);
buf[buflen - 1] = '\0'; buf[buflen - 1] = '\0';
break; break;
} }
@ -372,13 +372,13 @@ ip_address_to_lprt_repr (const ip_address *addr, unsigned short port, char *buf,
server. Use acceptport after RETR, to get the socket of data server. Use acceptport after RETR, to get the socket of data
connection. */ connection. */
uerr_t uerr_t
ftp_lprt (struct rbuf *rbuf) ftp_lprt (struct rbuf *rbuf, int *local_sock)
{ {
uerr_t err; uerr_t err;
char *request, *respline; char *request, *respline;
ip_address addr; ip_address addr;
int nwritten; int nwritten;
unsigned short port; int port;
/* Must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */ /* Must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
char bytes[21 * 4 + 1]; char bytes[21 * 4 + 1];
@ -395,7 +395,7 @@ ftp_lprt (struct rbuf *rbuf)
port = 0; port = 0;
/* Bind the port. */ /* Bind the port. */
err = bindport (&addr, &port); err = bindport (&addr, &port, local_sock);
if (err != BINDOK) if (err != BINDOK)
return err; return err;
@ -408,7 +408,7 @@ ftp_lprt (struct rbuf *rbuf)
if (nwritten < 0) if (nwritten < 0)
{ {
xfree (request); xfree (request);
closeport (-1); CLOSE (*local_sock);
return WRITEFAILED; return WRITEFAILED;
} }
xfree (request); xfree (request);
@ -417,13 +417,13 @@ ftp_lprt (struct rbuf *rbuf)
if (err != FTPOK) if (err != FTPOK)
{ {
xfree (respline); xfree (respline);
closeport (-1); CLOSE (*local_sock);
return err; return err;
} }
if (*respline != '2') if (*respline != '2')
{ {
xfree (respline); xfree (respline);
closeport (-1); CLOSE (*local_sock);
return FTPPORTERR; return FTPPORTERR;
} }
xfree (respline); xfree (respline);
@ -431,7 +431,7 @@ ftp_lprt (struct rbuf *rbuf)
} }
static void static void
ip_address_to_eprt_repr (const ip_address *addr, unsigned short port, char *buf, ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf,
size_t buflen) size_t buflen)
{ {
int afnum; int afnum;
@ -454,13 +454,13 @@ ip_address_to_eprt_repr (const ip_address *addr, unsigned short port, char *buf,
server. Use acceptport after RETR, to get the socket of data server. Use acceptport after RETR, to get the socket of data
connection. */ connection. */
uerr_t uerr_t
ftp_eprt (struct rbuf *rbuf) ftp_eprt (struct rbuf *rbuf, int *local_sock)
{ {
uerr_t err; uerr_t err;
char *request, *respline; char *request, *respline;
ip_address addr; ip_address addr;
int nwritten; int nwritten;
unsigned short port; int port;
/* Must contain the argument of EPRT (of the form |af|addr|port|). /* Must contain the argument of EPRT (of the form |af|addr|port|).
* 4 chars for the | separators, ENABLE_IPV6_ADDRSTRLEN chars for addr * 4 chars for the | separators, ENABLE_IPV6_ADDRSTRLEN chars for addr
* 1 char for af (1-2) and 5 chars for port (0-65535) */ * 1 char for af (1-2) and 5 chars for port (0-65535) */
@ -479,7 +479,7 @@ ftp_eprt (struct rbuf *rbuf)
port = 0; port = 0;
/* Bind the port. */ /* Bind the port. */
err = bindport (&addr, &port); err = bindport (&addr, &port, local_sock);
if (err != BINDOK) if (err != BINDOK)
return err; return err;
@ -492,7 +492,7 @@ ftp_eprt (struct rbuf *rbuf)
if (nwritten < 0) if (nwritten < 0)
{ {
xfree (request); xfree (request);
closeport (-1); CLOSE (*local_sock);
return WRITEFAILED; return WRITEFAILED;
} }
xfree (request); xfree (request);
@ -501,13 +501,13 @@ ftp_eprt (struct rbuf *rbuf)
if (err != FTPOK) if (err != FTPOK)
{ {
xfree (respline); xfree (respline);
closeport (-1); CLOSE (*local_sock);
return err; return err;
} }
if (*respline != '2') if (*respline != '2')
{ {
xfree (respline); xfree (respline);
closeport (-1); CLOSE (*local_sock);
return FTPPORTERR; return FTPPORTERR;
} }
xfree (respline); xfree (respline);
@ -519,7 +519,7 @@ ftp_eprt (struct rbuf *rbuf)
transfer. Reads the response from server and parses it. Reads the transfer. Reads the response from server and parses it. Reads the
host and port addresses and returns them. */ host and port addresses and returns them. */
uerr_t uerr_t
ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port) ftp_pasv (struct rbuf *rbuf, ip_address *addr, int *port)
{ {
char *request, *respline, *s; char *request, *respline, *s;
int nwritten, i; int nwritten, i;
@ -588,7 +588,7 @@ ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
transfer. Reads the response from server and parses it. Reads the transfer. Reads the response from server and parses it. Reads the
host and port addresses and returns them. */ host and port addresses and returns them. */
uerr_t uerr_t
ftp_lpsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port) ftp_lpsv (struct rbuf *rbuf, ip_address *addr, int *port)
{ {
char *request, *respline, *s; char *request, *respline, *s;
int nwritten, i, af, addrlen, portlen; int nwritten, i, af, addrlen, portlen;
@ -754,19 +754,19 @@ ftp_lpsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
transfer. Reads the response from server and parses it. Reads the transfer. Reads the response from server and parses it. Reads the
host and port addresses and returns them. */ host and port addresses and returns them. */
uerr_t uerr_t
ftp_epsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port) ftp_epsv (struct rbuf *rbuf, ip_address *ip, int *port)
{ {
char *request, *respline, *start, delim, *s; char *request, *respline, *start, delim, *s;
int nwritten, i; int nwritten, i;
uerr_t err; uerr_t err;
unsigned short tport; int tport;
socklen_t addrlen; socklen_t addrlen;
struct sockaddr_storage ss; struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr *)&ss; struct sockaddr *sa = (struct sockaddr *)&ss;
assert (rbuf != NULL); assert (rbuf != NULL);
assert (rbuf_initialized_p(rbuf)); assert (rbuf_initialized_p(rbuf));
assert (addr != NULL); assert (ip != NULL);
assert (port != NULL); assert (port != NULL);
addrlen = sizeof (ss); addrlen = sizeof (ss);
@ -776,7 +776,7 @@ ftp_epsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
assert (sa->sa_family == AF_INET || sa->sa_family == AF_INET6); assert (sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
sockaddr_get_address (sa, NULL, addr); sockaddr_get_data (sa, ip, NULL);
/* Form the request. */ /* Form the request. */
/* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */ /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */

107
src/ftp.c
View File

@ -143,7 +143,7 @@ getfamily (int fd)
* It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv. * It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv.
*/ */
static uerr_t static uerr_t
ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port) ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, int *port)
{ {
uerr_t err; uerr_t err;
int family; int family;
@ -183,7 +183,7 @@ ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
* It is merely a wrapper around ftp_eprt, ftp_lprt and ftp_port. * It is merely a wrapper around ftp_eprt, ftp_lprt and ftp_port.
*/ */
static uerr_t static uerr_t
ftp_do_port (struct rbuf *rbuf) ftp_do_port (struct rbuf *rbuf, int *local_sock)
{ {
uerr_t err; uerr_t err;
int family; int family;
@ -201,28 +201,42 @@ ftp_do_port (struct rbuf *rbuf)
{ {
if (!opt.server_response) if (!opt.server_response)
logputs (LOG_VERBOSE, "==> EPRT ... "); logputs (LOG_VERBOSE, "==> EPRT ... ");
err = ftp_eprt (rbuf); err = ftp_eprt (rbuf, local_sock);
/* If EPRT is not supported try LPRT */ /* If EPRT is not supported try LPRT */
if (err == FTPPORTERR) if (err == FTPPORTERR)
{ {
if (!opt.server_response) if (!opt.server_response)
logputs (LOG_VERBOSE, "==> LPRT ... "); logputs (LOG_VERBOSE, "==> LPRT ... ");
err = ftp_lprt (rbuf); err = ftp_lprt (rbuf, local_sock);
} }
} }
else else
{ {
if (!opt.server_response) if (!opt.server_response)
logputs (LOG_VERBOSE, "==> PORT ... "); logputs (LOG_VERBOSE, "==> PORT ... ");
err = ftp_port (rbuf); err = ftp_port (rbuf, local_sock);
} }
return err; return err;
} }
#else #else
#define ftp_do_pasv ftp_pasv
#define ftp_do_port ftp_port static uerr_t
ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, int *port)
{
if (!opt.server_response)
logputs (LOG_VERBOSE, "==> PASV ... ");
return ftp_pasv (rbuf, addr, port);
}
static uerr_t
ftp_do_port (struct rbuf *rbuf, int *local_sock)
{
if (!opt.server_response)
logputs (LOG_VERBOSE, "==> PORT ... ");
return ftp_port (rbuf, local_sock);
}
#endif #endif
/* Retrieves a file with denoted parameters through opening an FTP /* Retrieves a file with denoted parameters through opening an FTP
@ -231,7 +245,7 @@ ftp_do_port (struct rbuf *rbuf)
static uerr_t static uerr_t
getftp (struct url *u, long *len, long restval, ccon *con) getftp (struct url *u, long *len, long restval, ccon *con)
{ {
int csock, dtsock, res; int csock, dtsock, local_sock, res;
uerr_t err; uerr_t err;
FILE *fp; FILE *fp;
char *user, *passwd, *respline; char *user, *passwd, *respline;
@ -258,6 +272,7 @@ getftp (struct url *u, long *len, long restval, ccon *con)
assert (user && passwd); assert (user && passwd);
dtsock = -1; dtsock = -1;
local_sock = -1;
con->dltime = 0; con->dltime = 0;
if (!(cmd & DO_LOGIN)) if (!(cmd & DO_LOGIN))
@ -265,8 +280,6 @@ 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;
char *host = con->proxy ? con->proxy->host : u->host; char *host = con->proxy ? con->proxy->host : u->host;
int port = con->proxy ? con->proxy->port : u->port; int port = con->proxy ? con->proxy->port : u->port;
char *logname = user; char *logname = user;
@ -282,15 +295,10 @@ getftp (struct url *u, long *len, long restval, ccon *con)
/* First: Establish the control connection. */ /* First: Establish the control connection. */
al = lookup_host (host, 0); csock = connect_to_host (host, port);
if (!al) if (csock == E_HOST)
return HOSTERR; return HOSTERR;
set_connection_host_name (host); else if (csock < 0)
csock = connect_to_many (al, port, 0);
set_connection_host_name (NULL);
address_list_release (al);
if (csock < 0)
return CONNECT_ERROR (errno); return CONNECT_ERROR (errno);
if (cmd & LEAVE_PENDING) if (cmd & LEAVE_PENDING)
@ -643,9 +651,7 @@ Error in server response, closing control connection.\n"));
if (opt.ftp_pasv > 0) if (opt.ftp_pasv > 0)
{ {
ip_address passive_addr; ip_address passive_addr;
unsigned short passive_port; int passive_port;
if (!opt.server_response)
logputs (LOG_VERBOSE, "==> PASV ... ");
err = ftp_do_pasv (&con->rbuf, &passive_addr, &passive_port); err = ftp_do_pasv (&con->rbuf, &passive_addr, &passive_port);
/* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */ /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */
switch (err) switch (err)
@ -686,7 +692,7 @@ Error in server response, closing control connection.\n"));
DEBUGP (("trying to connect to %s port %d\n", DEBUGP (("trying to connect to %s port %d\n",
pretty_print_address (&passive_addr), pretty_print_address (&passive_addr),
passive_port)); passive_port));
dtsock = connect_to_one (&passive_addr, passive_port, 1); dtsock = connect_to_ip (&passive_addr, passive_port, NULL);
if (dtsock < 0) if (dtsock < 0)
{ {
int save_errno = errno; int save_errno = errno;
@ -706,9 +712,7 @@ Error in server response, closing control connection.\n"));
if (!pasv_mode_open) /* Try to use a port command if PASV failed */ if (!pasv_mode_open) /* Try to use a port command if PASV failed */
{ {
if (!opt.server_response) err = ftp_do_port (&con->rbuf, &local_sock);
logputs (LOG_VERBOSE, "==> PORT ... ");
err = ftp_do_port (&con->rbuf);
/* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR, /* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR,
LISTENERR), HOSTERR, FTPPORTERR */ LISTENERR), HOSTERR, FTPPORTERR */
switch (err) switch (err)
@ -718,7 +722,8 @@ Error in server response, closing control connection.\n"));
logputs (LOG_NOTQUIET, _("\ logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n")); Error in server response, closing control connection.\n"));
CLOSE (csock); CLOSE (csock);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
return err; return err;
break; break;
@ -727,7 +732,8 @@ Error in server response, closing control connection.\n"));
logputs (LOG_NOTQUIET, logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n")); _("Write failed, closing control connection.\n"));
CLOSE (csock); CLOSE (csock);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
return err; return err;
break; break;
@ -735,7 +741,8 @@ Error in server response, closing control connection.\n"));
logputs (LOG_VERBOSE, "\n"); logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno)); logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
CLOSE (csock); CLOSE (csock);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
return err; return err;
break; break;
@ -744,14 +751,16 @@ Error in server response, closing control connection.\n"));
logputs (LOG_VERBOSE, "\n"); logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"), logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"),
strerror (errno)); strerror (errno));
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
return err; return err;
break; break;
case FTPPORTERR: case FTPPORTERR:
logputs (LOG_VERBOSE, "\n"); logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("Invalid PORT.\n")); logputs (LOG_NOTQUIET, _("Invalid PORT.\n"));
CLOSE (csock); CLOSE (csock);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
return err; return err;
break; break;
@ -782,7 +791,8 @@ Error in server response, closing control connection.\n"));
logputs (LOG_NOTQUIET, _("\ logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n")); Error in server response, closing control connection.\n"));
CLOSE (csock); CLOSE (csock);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
return err; return err;
break; break;
@ -791,7 +801,8 @@ Error in server response, closing control connection.\n"));
logputs (LOG_NOTQUIET, logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n")); _("Write failed, closing control connection.\n"));
CLOSE (csock); CLOSE (csock);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
return err; return err;
break; break;
@ -805,7 +816,8 @@ Error in server response, closing control connection.\n"));
_("\nREST failed; will not truncate `%s'.\n"), _("\nREST failed; will not truncate `%s'.\n"),
con->target); con->target);
CLOSE (csock); CLOSE (csock);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
return CONTNOTSUPPORTED; return CONTNOTSUPPORTED;
} }
@ -832,7 +844,8 @@ Error in server response, closing control connection.\n"));
if (opt.spider) if (opt.spider)
{ {
CLOSE (csock); CLOSE (csock);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
return RETRFINISHED; return RETRFINISHED;
} }
@ -856,7 +869,8 @@ Error in server response, closing control connection.\n"));
logputs (LOG_NOTQUIET, _("\ logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n")); Error in server response, closing control connection.\n"));
CLOSE (csock); CLOSE (csock);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
return err; return err;
break; break;
@ -865,14 +879,16 @@ Error in server response, closing control connection.\n"));
logputs (LOG_NOTQUIET, logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n")); _("Write failed, closing control connection.\n"));
CLOSE (csock); CLOSE (csock);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
return err; return err;
break; break;
case FTPNSFOD: case FTPNSFOD:
logputs (LOG_VERBOSE, "\n"); logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, _("No such file `%s'.\n\n"), u->file); logprintf (LOG_NOTQUIET, _("No such file `%s'.\n\n"), u->file);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
return err; return err;
break; break;
case FTPOK: case FTPOK:
@ -904,7 +920,8 @@ Error in server response, closing control connection.\n"));
logputs (LOG_NOTQUIET, _("\ logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n")); Error in server response, closing control connection.\n"));
CLOSE (csock); CLOSE (csock);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
return err; return err;
break; break;
@ -913,7 +930,8 @@ Error in server response, closing control connection.\n"));
logputs (LOG_NOTQUIET, logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n")); _("Write failed, closing control connection.\n"));
CLOSE (csock); CLOSE (csock);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
return err; return err;
break; break;
@ -921,7 +939,8 @@ Error in server response, closing control connection.\n"));
logputs (LOG_VERBOSE, "\n"); logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, _("No such file or directory `%s'.\n\n"), logprintf (LOG_NOTQUIET, _("No such file or directory `%s'.\n\n"),
"."); ".");
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
return err; return err;
break; break;
case FTPOK: case FTPOK:
@ -953,7 +972,7 @@ Error in server response, closing control connection.\n"));
to accept */ to accept */
{ {
/* Open the data transmission socket by calling acceptport(). */ /* Open the data transmission socket by calling acceptport(). */
err = acceptport (&dtsock); err = acceptport (local_sock, &dtsock);
/* Possible errors: ACCEPTERR. */ /* Possible errors: ACCEPTERR. */
if (err == ACCEPTERR) if (err == ACCEPTERR)
{ {
@ -977,7 +996,8 @@ Error in server response, closing control connection.\n"));
logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, strerror (errno)); logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, strerror (errno));
CLOSE (csock); CLOSE (csock);
rbuf_uninitialize (&con->rbuf); rbuf_uninitialize (&con->rbuf);
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
return FOPENERR; return FOPENERR;
} }
} }
@ -1024,7 +1044,8 @@ Error in server response, closing control connection.\n"));
tms = time_str (NULL); tms = time_str (NULL);
tmrate = retr_rate (*len - restval, con->dltime, 0); tmrate = retr_rate (*len - restval, con->dltime, 0);
/* Close data connection socket. */ /* Close data connection socket. */
closeport (dtsock); CLOSE (dtsock);
CLOSE (local_sock);
/* Close the local file. */ /* Close the local file. */
{ {
/* Close or flush the file. We have to be careful to check for /* Close or flush the file. We have to be careful to check for

View File

@ -48,13 +48,13 @@ enum stype
uerr_t ftp_response PARAMS ((struct rbuf *, char **)); uerr_t ftp_response PARAMS ((struct rbuf *, char **));
uerr_t ftp_login PARAMS ((struct rbuf *, const char *, const char *)); uerr_t ftp_login PARAMS ((struct rbuf *, const char *, const char *));
uerr_t ftp_port PARAMS ((struct rbuf *)); uerr_t ftp_port PARAMS ((struct rbuf *, int *));
uerr_t ftp_pasv PARAMS ((struct rbuf *, ip_address *, unsigned short *)); uerr_t ftp_pasv PARAMS ((struct rbuf *, ip_address *, int *));
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
uerr_t ftp_lprt PARAMS ((struct rbuf *)); uerr_t ftp_lprt PARAMS ((struct rbuf *, int *));
uerr_t ftp_lpsv PARAMS ((struct rbuf *, ip_address *, unsigned short *)); uerr_t ftp_lpsv PARAMS ((struct rbuf *, ip_address *, int *));
uerr_t ftp_eprt PARAMS ((struct rbuf *)); uerr_t ftp_eprt PARAMS ((struct rbuf *, int *));
uerr_t ftp_epsv PARAMS ((struct rbuf *, ip_address *, unsigned short *)); uerr_t ftp_epsv PARAMS ((struct rbuf *, ip_address *, int *));
#endif #endif
uerr_t ftp_type PARAMS ((struct rbuf *, int)); uerr_t ftp_type PARAMS ((struct rbuf *, int));
uerr_t ftp_cwd PARAMS ((struct rbuf *, const char *)); uerr_t ftp_cwd PARAMS ((struct rbuf *, const char *));

View File

@ -6,7 +6,7 @@ This file is part of GNU Wget.
GNU Wget is free software; you can redistribute it and/or modify GNU Wget is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
GNU Wget is distributed in the hope that it will be useful, GNU Wget is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
@ -99,7 +99,11 @@ struct address_list {
ip_address *addresses; /* pointer to the string of addresses */ ip_address *addresses; /* pointer to the string of addresses */
int faulty; /* number of addresses known not to work. */ int faulty; /* number of addresses known not to work. */
int refcount; /* so we know whether to free it or not. */ int from_cache; /* whether this entry was pulled from
cache or freshly looked up. */
int refcount; /* reference count; when it drops to
0, the entry is freed. */
}; };
/* Get the bounds of the address list. */ /* Get the bounds of the address list. */
@ -111,14 +115,22 @@ address_list_get_bounds (const struct address_list *al, int *start, int *end)
*end = al->count; *end = al->count;
} }
/* Copy address number INDEX to IP_STORE. */ /* Return whether this address list entry has been obtained from the
cache. */
void int
address_list_copy_one (const struct address_list *al, int index, address_list_cached_p (const struct address_list *al)
ip_address *ip_store)
{ {
assert (index >= al->faulty && index < al->count); return al->from_cache;
memcpy (ip_store, al->addresses + index, sizeof (ip_address)); }
/* Return a pointer to the address at position POS. */
const ip_address *
address_list_address_at (const struct address_list *al, int pos)
{
assert (pos >= al->faulty && pos < al->count);
return al->addresses + pos;
} }
/* Check whether two address lists have all their IPs in common. */ /* Check whether two address lists have all their IPs in common. */
@ -204,7 +216,7 @@ address_list_set_faulty (struct address_list *al, int index)
* This function transform an addrinfo links list in and address_list. * This function transform an addrinfo links list in and address_list.
* *
* Input: * Input:
* addrinfo* Linkt list of addrinfo * addrinfo* Linked list of addrinfo
* *
* Output: * Output:
* address_list* New allocated address_list * address_list* New allocated address_list
@ -228,6 +240,7 @@ address_list_from_addrinfo (const struct addrinfo *ai)
al->addresses = xmalloc (cnt * sizeof (ip_address)); al->addresses = xmalloc (cnt * sizeof (ip_address));
al->count = cnt; al->count = cnt;
al->faulty = 0; al->faulty = 0;
al->from_cache = 0;
al->refcount = 1; al->refcount = 1;
ip = al->addresses; ip = al->addresses;
@ -271,6 +284,7 @@ address_list_from_vector (char **h_addr_list)
al->count = count; al->count = count;
al->faulty = 0; al->faulty = 0;
al->addresses = xmalloc (count * sizeof (ip_address)); al->addresses = xmalloc (count * sizeof (ip_address));
al->from_cache = 0;
al->refcount = 1; al->refcount = 1;
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
@ -293,6 +307,7 @@ address_list_from_single (const ip_address *addr)
al->count = 1; al->count = 1;
al->faulty = 0; al->faulty = 0;
al->addresses = xmalloc (sizeof (ip_address)); al->addresses = xmalloc (sizeof (ip_address));
al->from_cache = 0;
al->refcount = 1; al->refcount = 1;
memcpy (al->addresses, addr, sizeof (ip_address)); memcpy (al->addresses, addr, sizeof (ip_address));
@ -319,203 +334,6 @@ address_list_release (struct address_list *al)
} }
} }
/**
* sockaddr_set_address
*
* This function takes a sockaddr struct and fills in the protocol type,
* the port number and the address. If ENABLE_IPV6 is defined, the sa
* parameter should point to a sockaddr_storage structure; if not, it
* should point to a sockaddr_in structure.
* If the address parameter is NULL, the function will use the unspecified
* address (0.0.0.0 for IPv4 and :: for IPv6).
* Unsupported address family will abort the whole programm.
*
* Input:
* struct sockaddr* The space to be filled
* unsigned short The port
* const ip_address The IP address
*
* Return:
* - Only modifies 1st parameter.
*/
void
sockaddr_set_address (struct sockaddr *sa, unsigned short port,
const ip_address *addr)
{
if (addr->type == IPV4_ADDRESS)
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
sin->sin_family = AF_INET;
sin->sin_port = htons (port);
if (addr == NULL)
sin->sin_addr.s_addr = INADDR_ANY;
else
sin->sin_addr = ADDRESS_IPV4_IN_ADDR (addr);
}
#ifdef ENABLE_IPV6
else if (addr->type == IPV6_ADDRESS)
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons (port);
/* #### How can ADDR be NULL? We have dereferenced it above by
accessing addr->type! */
if (addr == NULL)
{
sin6->sin6_addr = in6addr_any;
/* #### Should we set the scope_id here? */
}
else
{
sin6->sin6_addr = ADDRESS_IPV6_IN6_ADDR (addr);
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
sin6->sin6_scope_id = ADDRESS_IPV6_SCOPE (addr);
#endif
}
}
#endif /* ENABLE_IPV6 */
else
abort ();
}
void
sockaddr_get_address (const struct sockaddr *sa, unsigned short *port,
ip_address *addr)
{
if (sa->sa_family == AF_INET)
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
addr->type = IPV4_ADDRESS;
ADDRESS_IPV4_IN_ADDR (addr) = sin->sin_addr;
if (port != NULL)
*port = ntohs (sin->sin_port);
}
#ifdef ENABLE_IPV6
else if (sa->sa_family == AF_INET6)
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
addr->type = IPV6_ADDRESS;
ADDRESS_IPV6_IN6_ADDR (addr) = sin6->sin6_addr;
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
ADDRESS_IPV6_SCOPE (addr) = sin6->sin6_scope_id;
#endif
if (port != NULL)
*port = ntohs (sin6->sin6_port);
}
#endif
else
abort ();
}
#if 0 /* currently unused */
/**
* sockaddr_set_port
*
* This funtion only fill the port of the socket information.
* If the protocol is not supported nothing is done.
* Unsuported adress family will abort the whole programm.
*
* Require:
* that the IP-Protocol already is set.
*
* Input:
* wget_sockaddr* The space there port should be entered
* unsigned int The port that should be entered in host order
*
* Return:
* - Only modify 1. param
*/
void
sockaddr_set_port (struct sockaddr *sa, unsigned short port)
{
if (sa->sa_family == AF_INET)
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
sin->sin_port = htons (port);
}
#ifdef ENABLE_IPV6
else if (sa->sa_family == AF_INET6)
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
sin6->sin6_port = htons (port);
}
#endif
else
abort ();
}
#endif
/**
* sockaddr_get_port
*
* This function only return the port from the input structure
* Unsuported adress family will abort the whole programm.
*
* Require:
* that the IP-Protocol already is set.
*
* Input:
* wget_sockaddr* Information where to get the port
*
* Output:
* unsigned short Port Number in host order.
*/
unsigned short
sockaddr_get_port (const struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
return htons (sin->sin_port);
#ifdef ENABLE_IPV6
} else if (sa->sa_family == AF_INET6) {
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
return htons (sin6->sin6_port);
#endif
} else
abort ();
/* do not complain about return nothing */
return -1;
}
/**
* sockaddr_len
*
* This function return the length of the sockaddr corresponding to
* the acutall prefered protocol for (bind, connect etc...)
* Unsuported adress family will abort the whole programm.
*
* Require:
* that the IP-Protocol already is set.
*
* Input:
* - Public IP-Family Information
*
* Output:
* int structure length for socket options
*/
socklen_t
sockaddr_len (const struct sockaddr *sa)
{
if (sa->sa_family == AF_INET)
{
return sizeof (struct sockaddr_in);
}
#ifdef ENABLE_IPV6
else if (sa->sa_family == AF_INET6)
{
return sizeof (struct sockaddr_in6);
}
#endif
else
abort ();
/* do not complain about return nothing */
return 0;
}
/* Versions of gethostbyname and getaddrinfo that support timeout. */ /* Versions of gethostbyname and getaddrinfo that support timeout. */
#ifndef ENABLE_IPV6 #ifndef ENABLE_IPV6
@ -655,6 +473,17 @@ cache_host_lookup (const char *host, struct address_list *al)
#endif #endif
} }
void
forget_host_lookup (const char *host)
{
struct address_list *al = hash_table_get (host_name_addresses_map, host);
if (al)
{
address_list_release (al);
hash_table_remove (host_name_addresses_map, host);
}
}
struct address_list * struct address_list *
lookup_host (const char *host, int flags) lookup_host (const char *host, int flags)
{ {
@ -724,6 +553,7 @@ lookup_host (const char *host, int flags)
{ {
DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al)); DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
++al->refcount; ++al->refcount;
al->from_cache = 1;
return al; return al;
} }
} }

View File

@ -84,12 +84,6 @@ typedef struct {
#define ADDRESS_IPV4_IN_ADDR(x) ((x)->u.ipv4.addr) #define ADDRESS_IPV4_IN_ADDR(x) ((x)->u.ipv4.addr)
#define ADDRESS_IPV4_DATA(x) ((void *)&(x)->u.ipv4.addr.s_addr) #define ADDRESS_IPV4_DATA(x) ((void *)&(x)->u.ipv4.addr.s_addr)
#ifndef ENABLE_IPV6
# ifndef HAVE_SOCKADDR_STORAGE
# define sockaddr_storage sockaddr_in
# endif
#endif /* ENABLE_IPV6 */
/* Flags for lookup_host */ /* Flags for lookup_host */
#define LH_SILENT 0x0001 #define LH_SILENT 0x0001
#define LH_PASSIVE 0x0002 #define LH_PASSIVE 0x0002
@ -100,10 +94,13 @@ typedef struct {
struct address_list *lookup_host PARAMS ((const char *, int)); struct address_list *lookup_host PARAMS ((const char *, int));
char *herrmsg PARAMS ((int)); char *herrmsg PARAMS ((int));
void forget_host_lookup PARAMS ((const char *));
void address_list_get_bounds PARAMS ((const struct address_list *, void address_list_get_bounds PARAMS ((const struct address_list *,
int *, int *)); int *, int *));
void address_list_copy_one PARAMS ((const struct address_list *, int, int address_list_cached_p PARAMS ((const struct address_list *));
ip_address *)); const ip_address *address_list_address_at PARAMS ((const struct address_list *,
int));
int address_list_match_all PARAMS ((const struct address_list *, int address_list_match_all PARAMS ((const struct address_list *,
const struct address_list *)); const struct address_list *));
void address_list_set_faulty PARAMS ((struct address_list *, int)); void address_list_set_faulty PARAMS ((struct address_list *, int));
@ -114,13 +111,6 @@ const char *pretty_print_address PARAMS ((const ip_address *));
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 *));
void sockaddr_set_address PARAMS ((struct sockaddr *, unsigned short,
const ip_address *));
void sockaddr_get_address PARAMS ((const struct sockaddr *, unsigned short *,
ip_address *));
unsigned short sockaddr_get_port PARAMS ((const struct sockaddr *));
socklen_t sockaddr_len PARAMS ((const struct sockaddr *sa));
void host_cleanup PARAMS ((void)); void host_cleanup PARAMS ((void));
#endif /* HOST_H */ #endif /* HOST_H */

View File

@ -744,15 +744,10 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
#endif /* HAVE_SSL */ #endif /* HAVE_SSL */
) )
{ {
struct address_list *al = lookup_host (conn->host, 0); sock = connect_to_host (conn->host, conn->port);
if (!al) if (sock == E_HOST)
return HOSTERR; return HOSTERR;
set_connection_host_name (conn->host); else if (sock < 0)
sock = connect_to_many (al, conn->port, 0);
set_connection_host_name (NULL);
address_list_release (al);
if (sock < 0)
return CONNECT_ERROR (errno); return CONNECT_ERROR (errno);
#ifdef HAVE_SSL #ifdef HAVE_SSL

View File

@ -111,8 +111,8 @@ so, delete this exception statement from your version. */
#ifdef __BEOS__ #ifdef __BEOS__
# undef READ # undef READ
# undef WRITE # undef WRITE
# define READ(fd, buf, cnt) recv((fd), (buf), (cnt), 0) # define READ(fd, buf, cnt) recv ((fd), (buf), (cnt), 0)
# define WRITE(fd, buf, cnt) send((fd), (buf), (cnt), 0) # define WRITE(fd, buf, cnt) send ((fd), (buf), (cnt), 0)
#endif #endif
/* mswindows.h defines these. */ /* mswindows.h defines these. */
@ -126,10 +126,13 @@ so, delete this exception statement from your version. */
# define REALCLOSE(x) close (x) # define REALCLOSE(x) close (x)
#endif #endif
#define CLOSE(x) \ #define CLOSE(x) do { \
do { \ int C_sock = (x); \
REALCLOSE (x); \ if (C_sock >= 0) \
DEBUGP (("Closing fd %d\n", x)); \ { \
REALCLOSE (C_sock); \
DEBUGP (("Closing fd %d\n", C_sock)); \
} \
} while (0) } while (0)
/* Define a large integral type useful for storing large sizes that /* Define a large integral type useful for storing large sizes that