]> sjero.net Git - wget/commitdiff
[svn] Networking improvements: get rid of the MSOCK global variable,
authorhniksic <devnull@localhost>
Fri, 31 Oct 2003 00:18:08 +0000 (16:18 -0800)
committerhniksic <devnull@localhost>
Fri, 31 Oct 2003 00:18:08 +0000 (16:18 -0800)
move the sockaddr handling to connect.c, make sure Wget refreshes
the DNS lookup after it becomes stale.

src/ChangeLog
src/connect.c
src/connect.h
src/ftp-basic.c
src/ftp.c
src/ftp.h
src/host.c
src/host.h
src/http.c
src/sysdep.h

index 3c80d28a62d1df9d42174545a14f87c915ebf993..613e4252e4ddc02408617a64e32ae2d18ec78173 100644 (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>
 
        * sysdep.h: Use `S >= 8' rather than `S == 8' when looking for
index 7e52b691c103c1cee3736b28d40bf36151196038..89a85f2f777cd2fc4d6c73462c76f4b5a71488d6 100644 (file)
@@ -6,7 +6,7 @@ This file is part of GNU Wget.
 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
 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,
 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;
 #endif
 
-/* Variables shared by bindport and acceptport: */
-static int msock = -1;
-/*static struct sockaddr *addr;*/
-
-static int
-resolve_bind_address (int flags, ip_address *addr)
+\f
+/**
+  * sockaddr_set_data
+  *
+  * This function takes a sockaddr struct and fills in the protocol
+  * 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;
-  int resolved = 0;
+  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 ();
+}
+
+/* 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.  */
 
-  if (opt.bind_address != NULL)
+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) 
     {
-      al = lookup_host (opt.bind_address, flags | LH_SILENT | LH_PASSIVE);
-      if (al == NULL)
-        {
-          logprintf (LOG_NOTQUIET,
-                    _("Unable to convert `%s' to a bind address.  Reverting to ANY.\n"),
-                    opt.bind_address);
+      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
        }
-      else 
-        resolved = 1;
+      if (port)
+       *port = ntohs (sin6->sin6_port);
     }
+#endif  
+  else
+    abort ();
+}
 
-  if (al == NULL)
+/* Return the size of the sockaddr structure depending on its
+   family.  */
+
+static socklen_t
+sockaddr_size (const struct sockaddr *sa)
+{
+  switch (sa->sa_family)
     {
-      /* #### Is there really a need for this?  Shouldn't we simply
-        return 0 and have the caller use sockaddr_set_address to
-        specify INADDR_ANY/in6addr_any?  */
-      const char *unspecified_address = "0.0.0.0";
+    case AF_INET:
+      return sizeof (struct sockaddr_in);
 #ifdef ENABLE_IPV6
-      if (flags & BIND_ON_IPV6_ONLY)
-       unspecified_address = "::";
+    case AF_INET6:
+      return sizeof (struct sockaddr_in6);
 #endif
-      al = lookup_host (unspecified_address, LH_SILENT | LH_PASSIVE);
+    default:
+      abort ();
+      return 0;                        /* so the compiler shuts up. */
     }
+}
+\f
+static int
+resolve_bind_address (const char *host, struct sockaddr *sa, int flags)
+{
+  struct address_list *al;
 
-  assert (al != NULL);
+  /* #### Shouldn't we do this only once?  opt.bind_address won't
+     change during a Wget run!  */
 
-  address_list_copy_one (al, 0, addr);
-  address_list_release (al);
+  al = lookup_host (host, flags | LH_SILENT | LH_PASSIVE);
+  if (al == NULL)
+    {
+      logprintf (LOG_NOTQUIET,
+                _("Unable to convert `%s' to a bind address.  Reverting to ANY.\n"),
+                opt.bind_address);
+      return 0;
+    }
 
-  return resolved;
+  /* Pick the first address in the list and use it as bind address.
+     Perhaps we should try multiple addresses, but I don't think
+     that's necessary in practice.  */
+  sockaddr_set_data (sa, address_list_address_at (al, 0), 0);
+  address_list_release (al);
+  return 1;
 }
 \f
 struct cwt_context {
@@ -146,76 +241,61 @@ connect_with_timeout (int fd, const struct sockaddr *addr, socklen_t addrlen,
   return ctx.result;
 }
 \f
-/* A kludge, but still better than passing the host name all the way
-   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 endpoint whose IP address is known.  */
 
-/* Connect to a remote host whose address has been resolved. */
 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 *sa = (struct sockaddr *)&ss;
   int sock, save_errno;
 
-  /* Set port and protocol */
-  sockaddr_set_address (sa, port, addr);
-
-  if (!silent)
+  /* If PRINT is non-NULL, print the "Connecting to..." line, with
+     PRINT being the host name we're connecting to.  */
+  if (print)
     {
-      const 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);
+      const char *txt_addr = pretty_print_address (ip);
+      if (print && 0 != strcmp (print, txt_addr))
+       logprintf (LOG_VERBOSE,
+                  _("Connecting to %s{%s}:%d... "), print, txt_addr, port);
       else
-       logprintf (LOG_VERBOSE, _("Connecting to %s:%hu... "),
-                  pretty_addr, port);
+       logprintf (LOG_VERBOSE, _("Connecting to %s:%d... "), txt_addr, port);
     }
 
+  /* Store the sockaddr info to SA.  */
+  sockaddr_set_data (sa, ip, port);
+
   /* Create the socket of the family appropriate for the address.  */
   sock = socket (sa->sa_family, SOCK_STREAM, 0);
   if (sock < 0)
     goto out;
 
   /* For very small rate limits, set the buffer size (and hence,
-     hopefully, the size of the kernel window) to the size of the
-     limit.  That way we don't sleep for more than 1s between network
-     reads.  */
+     hopefully, the kernel's TCP window size) to the per-second limit.
+     That way we should never have to sleep for more than 1s between
+     network reads.  */
   if (opt.limit_rate && opt.limit_rate < 8192)
     {
       int bufsize = opt.limit_rate;
       if (bufsize < 512)
-       bufsize = 512;
+       bufsize = 512;          /* avoid pathologically small values */
 #ifdef SO_RCVBUF
       setsockopt (sock, SOL_SOCKET, SO_RCVBUF,
-                 (char *)&bufsize, sizeof (bufsize));
+                 (void *)&bufsize, (socklen_t)sizeof (bufsize));
 #endif
-      /* When we add opt.limit_rate support for writing, as with
-        `--post-file', also set SO_SNDBUF here.  */
+      /* When we add limit_rate support for writing, which is useful
+        for POST, we should also set SO_SNDBUF here.  */
     }
 
   if (opt.bind_address)
     {
-      /* Bind the client side to the requested address. */
-      ip_address bind_address;
-      if (resolve_bind_address (0, &bind_address))
-        {
-          struct sockaddr_storage bss;
-          struct sockaddr *bsa = (struct sockaddr *)&bss;
-          sockaddr_set_address (bsa, 0, &bind_address);
-          if (bind (sock, bsa, sockaddr_len (bsa)))
+      /* Bind the client side of the socket to the requested
+        address.  */
+      struct sockaddr_storage bind_ss;
+      struct sockaddr *bind_sa = (struct sockaddr *)&bind_ss;
+      if (resolve_bind_address (opt.bind_address, bind_sa, 0))
+       {
+          if (bind (sock, bind_sa, sockaddr_size (bind_sa)) < 0)
            {
              CLOSE (sock);
              sock = -1;
@@ -224,8 +304,8 @@ connect_to_one (ip_address *addr, unsigned short port, int silent)
        }
     }
 
-  /* Connect the socket to the remote host.  */
-  if (connect_with_timeout (sock, sa, sockaddr_len (sa),
+  /* Connect the socket to the remote endpoint.  */
+  if (connect_with_timeout (sock, sa, sockaddr_size (sa),
                            opt.connect_timeout) < 0)
     {
       CLOSE (sock);
@@ -237,14 +317,14 @@ connect_to_one (ip_address *addr, unsigned short port, int silent)
   if (sock >= 0)
     {
       /* Success. */
-      if (!silent)
+      if (print)
        logprintf (LOG_VERBOSE, _("connected.\n"));
       DEBUGP (("Created socket %d.\n", sock));
     }
   else
     {
       save_errno = errno;
-      if (!silent)
+      if (print)
        logprintf (LOG_VERBOSE, "failed: %s.\n", strerror (errno));
       errno = save_errno;
     }
@@ -252,31 +332,47 @@ connect_to_one (ip_address *addr, unsigned short port, int silent)
   return sock;
 }
 
-/* Connect to a remote host whose address has been resolved. */
+/* Connect to a remote endpoint specified by host name.  */
+
 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;
+  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);
   for (i = start; i < end; i++)
     {
-      ip_address addr;
-      int sock;
-      address_list_copy_one (al, i, &addr);
-
-      sock = connect_to_one (&addr, port, silent);
+      const ip_address *ip = address_list_address_at (al, i);
+      sock = connect_to_ip (ip, port, host);
       if (sock >= 0)
        /* Success. */
-       return sock;
+       break;
 
       address_list_set_faulty (al, i);
 
       /* The attempt to connect has failed.  Continue with the loop
         and try next address. */
     }
+  address_list_release (al);
+
+  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 -1;
+  return sock;
 }
 
 int
@@ -310,37 +406,36 @@ test_socket_open (int sock)
 #endif
 }
 
-/* Bind the local port PORT.  This does all the necessary work, which
-   is creating a socket, setting SO_REUSEADDR option on it, then
-   calling bind() and listen().  If *PORT is 0, a random port is
-   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.  */
+/* Create a socket and bind it to PORT locally.  Calling accept() on
+   such a socket waits for and accepts incoming TCP connections.  The
+   resulting socket is stored to LOCAL_SOCK.  */
 
 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 optval;
   struct sockaddr_storage ss;
   struct sockaddr *sa = (struct sockaddr *)&ss;
   memset (&ss, 0, sizeof (ss));
 
-  msock = -1;
-
 #ifdef ENABLE_IPV6
   if (bind_address->type == IPV6_ADDRESS) 
     family = AF_INET6;
 #endif
-  
+
   if ((msock = socket (family, SOCK_STREAM, 0)) < 0)
     return CONSOCKERR;
 
 #ifdef SO_REUSEADDR
   optval = 1;
   if (setsockopt (msock, SOL_SOCKET, SO_REUSEADDR,
-                 (char *)&optval, sizeof (optval)) < 0)
-    return CONSOCKERR;
+                 (void *)&optval, (socklen_t)sizeof (optval)) < 0)
+    {
+      CLOSE (msock);
+      return CONSOCKERR;
+    }
 #endif
 
 #ifdef ENABLE_IPV6
@@ -350,38 +445,36 @@ bindport (const ip_address *bind_address, unsigned short *port)
       optval = 1;
       /* if setsockopt fails, go on anyway */
       setsockopt (msock, IPPROTO_IPV6, IPV6_V6ONLY,
-                  (char *)&optval, sizeof (optval));
+                  (void *)&optval, (socklen_t)sizeof (optval));
     }
 # endif
 #endif
-  
-  sockaddr_set_address (sa, htons (*port), bind_address);
-  if (bind (msock, sa, sockaddr_len (sa)) < 0)
+
+  sockaddr_set_data (sa, bind_address, *port);
+  if (bind (msock, sa, sockaddr_size (sa)) < 0)
     {
       CLOSE (msock);
-      msock = -1;
       return BINDERR;
     }
-  DEBUGP (("Master socket fd %d bound.\n", msock));
+  DEBUGP (("Local socket fd %d bound.\n", msock));
   if (!*port)
     {
-      socklen_t sa_len = sockaddr_len (sa);
+      socklen_t sa_len = sockaddr_size (sa);
       if (getsockname (msock, sa, &sa_len) < 0)
        {
          CLOSE (msock);
-         msock = -1;
          return CONPORTERR;
        }
-      *port = sockaddr_get_port (sa);
+      sockaddr_get_data (sa, NULL, port);
       DEBUGP (("binding to address %s using port %i.\n", 
               pretty_print_address (bind_address), *port));
     }
   if (listen (msock, 1) < 0)
     {
       CLOSE (msock);
-      msock = -1;
       return LISTENERR;
     }
+  *local_sock = msock;
   return BINDOK;
 }
 
@@ -420,41 +513,28 @@ select_fd (int fd, double maxtime, int writep)
 }
 #endif /* HAVE_SELECT */
 
-/* Call accept() on MSOCK and store the result to *SOCK.  This assumes
-   that bindport() has been used to initialize MSOCK to a correct
-   value.  It blocks the caller until a connection is established.  If
-   no connection is established for OPT.CONNECT_TIMEOUT seconds, the
+/* Accept a connection on LOCAL_SOCK, and store the new socket to
+   *SOCK.  It blocks the caller until a connection is established.  If
+   no connection is established for opt.connect_timeout seconds, the
    function exits with an error status.  */
+
 uerr_t
-acceptport (int *sock)
+acceptport (int local_sock, int *sock)
 {
   struct sockaddr_storage ss;
   struct sockaddr *sa = (struct sockaddr *)&ss;
   socklen_t addrlen = sizeof (ss);
 
 #ifdef HAVE_SELECT
-  if (select_fd (msock, opt.connect_timeout, 0) <= 0)
+  if (select_fd (local_sock, opt.connect_timeout, 0) <= 0)
     return ACCEPTERR;
 #endif
-  if ((*sock = accept (msock, sa, &addrlen)) < 0)
+  if ((*sock = accept (local_sock, sa, &addrlen)) < 0)
     return ACCEPTERR;
   DEBUGP (("Created socket fd %d.\n", *sock));
   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.  */
 
 int
index a020bf253a63f77c82cf41019e6c92a91c5430e4..ab161c0b7d25061f4df56805f39aed0cf8ce460d 100644 (file)
@@ -6,7 +6,7 @@ This file is part of GNU Wget.
 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
 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,
 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 */
 
+/* Returned by connect_to_host when host name cannot be resolved.  */
+enum {
+  E_HOST = -100
+};
+
 /* bindport flags */
 #define BIND_ON_IPV4_ONLY LH_IPV4_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 */
 
-int connect_to_one PARAMS ((ip_address *, unsigned short, int));
-int connect_to_many PARAMS ((struct address_list *, unsigned short, int));
-void set_connection_host_name PARAMS ((const char *));
+int connect_to_ip PARAMS ((const ip_address *, int, const char *));
+int connect_to_host PARAMS ((const char *, int));
+
+void sockaddr_get_data PARAMS ((const struct sockaddr *, ip_address *, int *));
 
 int test_socket_open PARAMS ((int));
 int select_fd PARAMS ((int, double, int));
-uerr_t bindport PARAMS ((const ip_address *, unsigned short *));
-uerr_t acceptport PARAMS ((int *));
-void closeport PARAMS ((int));
+uerr_t bindport PARAMS ((const ip_address *, int *, int *));
+uerr_t acceptport PARAMS ((int, int *));
 int conaddr PARAMS ((int, ip_address *));
 
 int iread PARAMS ((int, char *, int));
index 8409579394b57ec4654e8739fd9f73ca0227bcb1..8d763ebb5d4e4b23e948a96f8152ae2ee78542df 100644 (file)
@@ -254,7 +254,7 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass)
 }
 
 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)
 {
   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);
   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';
 }
 
@@ -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
    connection.  */
 uerr_t
-ftp_port (struct rbuf *rbuf)
+ftp_port (struct rbuf *rbuf, int *local_sock)
 {
   uerr_t err;
   char *request, *respline;
   ip_address addr;
   int nwritten;
-  unsigned short port;
+  int port;
   /* Must contain the argument of PORT (of the form a,b,c,d,e,f). */
   char bytes[6 * 4 + 1];
 
@@ -298,7 +298,7 @@ ftp_port (struct rbuf *rbuf)
   port = 0;
 
   /* Bind the port.  */
-  err = bindport (&addr, &port);
+  err = bindport (&addr, &port, local_sock);
   if (err != BINDOK)
     return err;
 
@@ -311,7 +311,7 @@ ftp_port (struct rbuf *rbuf)
   if (nwritten < 0)
     {
       xfree (request);
-      closeport (-1);
+      CLOSE (*local_sock);
       return WRITEFAILED;
     }
   xfree (request);
@@ -321,13 +321,13 @@ ftp_port (struct rbuf *rbuf)
   if (err != FTPOK)
     {
       xfree (respline);
-      closeport (-1);
+      CLOSE (*local_sock);
       return err;
     }
   if (*respline != '2')
     {
       xfree (respline);
-      closeport (-1);
+      CLOSE (*local_sock);
       return FTPPORTERR;
     }
   xfree (respline);
@@ -336,7 +336,7 @@ ftp_port (struct rbuf *rbuf)
 
 #ifdef ENABLE_IPV6
 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)
 {
   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);
         snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4, 
                   ptr[0], ptr[1], ptr[2], ptr[3], 2,
-                  (unsigned) (port & 0xff00) >> 8, port & 0xff);
+                  (port & 0xff00) >> 8, port & 0xff);
         buf[buflen - 1] = '\0';
         break;
       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",
                  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,
-                 (unsigned) (port & 0xff00) >> 8, port & 0xff);
+                 (port & 0xff00) >> 8, port & 0xff);
        buf[buflen - 1] = '\0';
        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
    connection.  */
 uerr_t
-ftp_lprt (struct rbuf *rbuf)
+ftp_lprt (struct rbuf *rbuf, int *local_sock)
 {
   uerr_t err;
   char *request, *respline;
   ip_address addr;
   int nwritten;
-  unsigned short port;
+  int port;
   /* Must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
   char bytes[21 * 4 + 1];
 
@@ -395,7 +395,7 @@ ftp_lprt (struct rbuf *rbuf)
   port = 0;
 
   /* Bind the port.  */
-  err = bindport (&addr, &port);
+  err = bindport (&addr, &port, local_sock);
   if (err != BINDOK)
     return err;
 
@@ -408,7 +408,7 @@ ftp_lprt (struct rbuf *rbuf)
   if (nwritten < 0)
     {
       xfree (request);
-      closeport (-1);
+      CLOSE (*local_sock);
       return WRITEFAILED;
     }
   xfree (request);
@@ -417,13 +417,13 @@ ftp_lprt (struct rbuf *rbuf)
   if (err != FTPOK)
     {
       xfree (respline);
-      closeport (-1);
+      CLOSE (*local_sock);
       return err;
     }
   if (*respline != '2')
     {
       xfree (respline);
-      closeport (-1);
+      CLOSE (*local_sock);
       return FTPPORTERR;
     }
   xfree (respline);
@@ -431,7 +431,7 @@ ftp_lprt (struct rbuf *rbuf)
 }
 
 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)
 {
   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
    connection.  */
 uerr_t
-ftp_eprt (struct rbuf *rbuf)
+ftp_eprt (struct rbuf *rbuf, int *local_sock)
 {
   uerr_t err;
   char *request, *respline;
   ip_address addr;
   int nwritten;
-  unsigned short port;
+  int port;
   /* Must contain the argument of EPRT (of the form |af|addr|port|). 
    * 4 chars for the | separators, ENABLE_IPV6_ADDRSTRLEN chars for addr  
    * 1 char for af (1-2) and 5 chars for port (0-65535) */
@@ -479,7 +479,7 @@ ftp_eprt (struct rbuf *rbuf)
   port = 0;
 
   /* Bind the port.  */
-  err = bindport (&addr, &port);
+  err = bindport (&addr, &port, local_sock);
   if (err != BINDOK)
     return err;
 
@@ -492,7 +492,7 @@ ftp_eprt (struct rbuf *rbuf)
   if (nwritten < 0)
     {
       xfree (request);
-      closeport (-1);
+      CLOSE (*local_sock);
       return WRITEFAILED;
     }
   xfree (request);
@@ -501,13 +501,13 @@ ftp_eprt (struct rbuf *rbuf)
   if (err != FTPOK)
     {
       xfree (respline);
-      closeport (-1);
+      CLOSE (*local_sock);
       return err;
     }
   if (*respline != '2')
     {
       xfree (respline);
-      closeport (-1);
+      CLOSE (*local_sock);
       return FTPPORTERR;
     }
   xfree (respline);
@@ -519,7 +519,7 @@ ftp_eprt (struct rbuf *rbuf)
    transfer.  Reads the response from server and parses it.  Reads the
    host and port addresses and returns them.  */
 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;
   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
    host and port addresses and returns them.  */
 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;
   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
    host and port addresses and returns them.  */
 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;
   int nwritten, i;
   uerr_t err;
-  unsigned short tport;
+  int tport;
   socklen_t addrlen;
   struct sockaddr_storage ss;
   struct sockaddr *sa = (struct sockaddr *)&ss;
 
   assert (rbuf != NULL);
   assert (rbuf_initialized_p(rbuf));
-  assert (addr != NULL);
+  assert (ip != NULL);
   assert (port != NULL);
 
   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);
 
-  sockaddr_get_address (sa, NULL, addr);
+  sockaddr_get_data (sa, ip, NULL);
 
   /* Form the request.  */
   /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
index 8c3b4869e66d348f741751792908fecd03262fcd..69065490dda04d65cad29be4d108fd743a389094 100644 (file)
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -143,7 +143,7 @@ getfamily (int fd)
  * It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv.
  */
 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;
   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.
  */
 static uerr_t
-ftp_do_port (struct rbuf *rbuf)
+ftp_do_port (struct rbuf *rbuf, int *local_sock)
 {
   uerr_t err;
   int family;
@@ -201,28 +201,42 @@ ftp_do_port (struct rbuf *rbuf)
     {
       if (!opt.server_response)
         logputs (LOG_VERBOSE, "==> EPRT ... ");
-      err = ftp_eprt (rbuf);
+      err = ftp_eprt (rbuf, local_sock);
 
       /* If EPRT is not supported try LPRT */
       if (err == FTPPORTERR)
         {
           if (!opt.server_response)
             logputs (LOG_VERBOSE, "==> LPRT ... ");
-          err = ftp_lprt (rbuf);
+          err = ftp_lprt (rbuf, local_sock);
         }
     }
   else 
     {
       if (!opt.server_response)
         logputs (LOG_VERBOSE, "==> PORT ... ");
-      err = ftp_port (rbuf);
+      err = ftp_port (rbuf, local_sock);
     }
 
   return err;
 }
 #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
 
 /* Retrieves a file with denoted parameters through opening an FTP
@@ -231,7 +245,7 @@ ftp_do_port (struct rbuf *rbuf)
 static uerr_t
 getftp (struct url *u, long *len, long restval, ccon *con)
 {
-  int csock, dtsock, res;
+  int csock, dtsock, local_sock, res;
   uerr_t err;
   FILE *fp;
   char *user, *passwd, *respline;
@@ -258,6 +272,7 @@ getftp (struct url *u, long *len, long restval, ccon *con)
   assert (user && passwd);
 
   dtsock = -1;
+  local_sock = -1;
   con->dltime = 0;
 
   if (!(cmd & DO_LOGIN))
@@ -265,8 +280,6 @@ getftp (struct url *u, long *len, long restval, ccon *con)
   else                         /* cmd & DO_LOGIN */
     {
       char type_char;
-      struct address_list *al;
-
       char    *host = con->proxy ? con->proxy->host : u->host;
       int      port = con->proxy ? con->proxy->port : u->port;
       char *logname = user;
@@ -282,15 +295,10 @@ getftp (struct url *u, long *len, long restval, ccon *con)
 
       /* First: Establish the control connection.  */
 
-      al = lookup_host (host, 0);
-      if (!al)
+      csock = connect_to_host (host, port);
+      if (csock == E_HOST)
        return HOSTERR;
-      set_connection_host_name (host);
-      csock = connect_to_many (al, port, 0);
-      set_connection_host_name (NULL);
-      address_list_release (al);
-
-      if (csock < 0)
+      else if (csock < 0)
        return CONNECT_ERROR (errno);
 
       if (cmd & LEAVE_PENDING)
@@ -642,10 +650,8 @@ Error in server response, closing control connection.\n"));
     {
       if (opt.ftp_pasv > 0)
        {
-         ip_address     passive_addr;
-         unsigned short passive_port;
-         if (!opt.server_response)
-           logputs (LOG_VERBOSE, "==> PASV ... ");
+         ip_address passive_addr;
+         int        passive_port;
          err = ftp_do_pasv (&con->rbuf, &passive_addr, &passive_port);
          /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */
          switch (err)
@@ -686,7 +692,7 @@ Error in server response, closing control connection.\n"));
              DEBUGP (("trying to connect to %s port %d\n", 
                      pretty_print_address (&passive_addr),
                      passive_port));
-             dtsock = connect_to_one (&passive_addr, passive_port, 1);
+             dtsock = connect_to_ip (&passive_addr, passive_port, NULL);
              if (dtsock < 0)
                {
                  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 (!opt.server_response)
-           logputs (LOG_VERBOSE, "==> PORT ... ");
-         err = ftp_do_port (&con->rbuf);
+         err = ftp_do_port (&con->rbuf, &local_sock);
          /* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR,
             LISTENERR), HOSTERR, FTPPORTERR */
          switch (err)
@@ -718,7 +722,8 @@ Error in server response, closing control connection.\n"));
              logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
              CLOSE (csock);
-             closeport (dtsock);
+             CLOSE (dtsock);
+             CLOSE (local_sock);
              rbuf_uninitialize (&con->rbuf);
              return err;
              break;
@@ -727,7 +732,8 @@ Error in server response, closing control connection.\n"));
              logputs (LOG_NOTQUIET,
                       _("Write failed, closing control connection.\n"));
              CLOSE (csock);
-             closeport (dtsock);
+             CLOSE (dtsock);
+             CLOSE (local_sock);
              rbuf_uninitialize (&con->rbuf);
              return err;
              break;
@@ -735,7 +741,8 @@ Error in server response, closing control connection.\n"));
              logputs (LOG_VERBOSE, "\n");
              logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
              CLOSE (csock);
-             closeport (dtsock);
+             CLOSE (dtsock);
+             CLOSE (local_sock);
              rbuf_uninitialize (&con->rbuf);
              return err;
              break;
@@ -744,14 +751,16 @@ Error in server response, closing control connection.\n"));
              logputs (LOG_VERBOSE, "\n");
              logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"),
                         strerror (errno));
-             closeport (dtsock);
+             CLOSE (dtsock);
+             CLOSE (local_sock);
              return err;
              break;
            case FTPPORTERR:
              logputs (LOG_VERBOSE, "\n");
              logputs (LOG_NOTQUIET, _("Invalid PORT.\n"));
              CLOSE (csock);
-             closeport (dtsock);
+             CLOSE (dtsock);
+             CLOSE (local_sock);
              rbuf_uninitialize (&con->rbuf);
              return err;
              break;
@@ -782,7 +791,8 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
          CLOSE (csock);
-         closeport (dtsock);
+         CLOSE (dtsock);
+         CLOSE (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -791,7 +801,8 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_NOTQUIET,
                   _("Write failed, closing control connection.\n"));
          CLOSE (csock);
-         closeport (dtsock);
+         CLOSE (dtsock);
+         CLOSE (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -805,7 +816,8 @@ Error in server response, closing control connection.\n"));
                         _("\nREST failed; will not truncate `%s'.\n"),
                         con->target);
              CLOSE (csock);
-             closeport (dtsock);
+             CLOSE (dtsock);
+             CLOSE (local_sock);
              rbuf_uninitialize (&con->rbuf);
              return CONTNOTSUPPORTED;
            }
@@ -832,7 +844,8 @@ Error in server response, closing control connection.\n"));
       if (opt.spider)
        {
          CLOSE (csock);
-         closeport (dtsock);
+         CLOSE (dtsock);
+         CLOSE (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return RETRFINISHED;
        }
@@ -856,7 +869,8 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
          CLOSE (csock);
-         closeport (dtsock);
+         CLOSE (dtsock);
+         CLOSE (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -865,14 +879,16 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_NOTQUIET,
                   _("Write failed, closing control connection.\n"));
          CLOSE (csock);
-         closeport (dtsock);
+         CLOSE (dtsock);
+         CLOSE (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
        case FTPNSFOD:
          logputs (LOG_VERBOSE, "\n");
          logprintf (LOG_NOTQUIET, _("No such file `%s'.\n\n"), u->file);
-         closeport (dtsock);
+         CLOSE (dtsock);
+         CLOSE (local_sock);
          return err;
          break;
        case FTPOK:
@@ -904,7 +920,8 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
          CLOSE (csock);
-         closeport (dtsock);
+         CLOSE (dtsock);
+         CLOSE (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -913,7 +930,8 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_NOTQUIET,
                   _("Write failed, closing control connection.\n"));
          CLOSE (csock);
-         closeport (dtsock);
+         CLOSE (dtsock);
+         CLOSE (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -921,7 +939,8 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logprintf (LOG_NOTQUIET, _("No such file or directory `%s'.\n\n"),
                     ".");
-         closeport (dtsock);
+         CLOSE (dtsock);
+         CLOSE (local_sock);
          return err;
          break;
        case FTPOK:
@@ -953,7 +972,7 @@ Error in server response, closing control connection.\n"));
                              to accept */
     {
       /* Open the data transmission socket by calling acceptport().  */
-      err = acceptport (&dtsock);
+      err = acceptport (local_sock, &dtsock);
       /* Possible errors: 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));
          CLOSE (csock);
          rbuf_uninitialize (&con->rbuf);
-         closeport (dtsock);
+         CLOSE (dtsock);
+         CLOSE (local_sock);
          return FOPENERR;
        }
     }
@@ -1024,7 +1044,8 @@ Error in server response, closing control connection.\n"));
   tms = time_str (NULL);
   tmrate = retr_rate (*len - restval, con->dltime, 0);
   /* Close data connection socket.  */
-  closeport (dtsock);
+  CLOSE (dtsock);
+  CLOSE (local_sock);
   /* Close the local file.  */
   {
     /* Close or flush the file.  We have to be careful to check for
index 33c4c419210fb50d1bc2263f0725eb44adbd19db..78460016711a660b2bbe08af6f009c9463f3bacc 100644 (file)
--- a/src/ftp.h
+++ b/src/ftp.h
@@ -48,13 +48,13 @@ enum stype
   
 uerr_t ftp_response PARAMS ((struct rbuf *, char **));
 uerr_t ftp_login PARAMS ((struct rbuf *, const char *, const char *));
-uerr_t ftp_port PARAMS ((struct rbuf *));
-uerr_t ftp_pasv PARAMS ((struct rbuf *, ip_address *, unsigned short *));
+uerr_t ftp_port PARAMS ((struct rbuf *, int *));
+uerr_t ftp_pasv PARAMS ((struct rbuf *, ip_address *, int *));
 #ifdef ENABLE_IPV6
-uerr_t ftp_lprt PARAMS ((struct rbuf *));
-uerr_t ftp_lpsv PARAMS ((struct rbuf *, ip_address *, unsigned short *));
-uerr_t ftp_eprt PARAMS ((struct rbuf *));
-uerr_t ftp_epsv PARAMS ((struct rbuf *, ip_address *, unsigned short *));
+uerr_t ftp_lprt PARAMS ((struct rbuf *, int *));
+uerr_t ftp_lpsv PARAMS ((struct rbuf *, ip_address *, int *));
+uerr_t ftp_eprt PARAMS ((struct rbuf *, int *));
+uerr_t ftp_epsv PARAMS ((struct rbuf *, ip_address *, int *));
 #endif
 uerr_t ftp_type PARAMS ((struct rbuf *, int));
 uerr_t ftp_cwd PARAMS ((struct rbuf *, const char *));
index 62088aefd657ab336a14b8b4ba39cdbe88063829..937d72c800e3e35c0826124f1846294ceea0abfa 100644 (file)
@@ -6,7 +6,7 @@ This file is part of GNU Wget.
 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
 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,
 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 */
 
   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.  */
@@ -111,14 +115,22 @@ address_list_get_bounds (const struct address_list *al, int *start, int *end)
   *end   = al->count;
 }
 
-/* Copy address number INDEX to IP_STORE.  */
+/* Return whether this address list entry has been obtained from the
+   cache.  */
 
-void
-address_list_copy_one (const struct address_list *al, int index,
-                      ip_address *ip_store)
+int
+address_list_cached_p (const struct address_list *al)
+{
+  return al->from_cache;
+}
+
+/* Return a pointer to the address at position POS.  */
+
+const ip_address *
+address_list_address_at (const struct address_list *al, int pos)
 {
-  assert (index >= al->faulty && index < al->count);
-  memcpy (ip_store, al->addresses + index, sizeof (ip_address));
+  assert (pos >= al->faulty && pos < al->count);
+  return al->addresses + pos;
 }
 
 /* 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.
   *
   * Input:
-  * addrinfo*          Linkt list of addrinfo
+  * addrinfo*          Linked list of addrinfo
   *
   * Output:
   * address_list*      New allocated address_list
@@ -225,10 +237,11 @@ address_list_from_addrinfo (const struct addrinfo *ai)
     return NULL;
 
   al = xmalloc (sizeof (struct address_list));
-  al->addresses = xmalloc (cnt * sizeof (ip_address));
-  al->count     = cnt;
-  al->faulty    = 0;
-  al->refcount  = 1;
+  al->addresses  = xmalloc (cnt * sizeof (ip_address));
+  al->count      = cnt;
+  al->faulty     = 0;
+  al->from_cache = 0;
+  al->refcount   = 1;
 
   ip = al->addresses;
   for (ptr = ai; ptr != NULL; ptr = ptr->ai_next)
@@ -268,10 +281,11 @@ address_list_from_vector (char **h_addr_list)
     ++count;
   assert (count > 0);
 
-  al->count     = count;
-  al->faulty    = 0;
-  al->addresses = xmalloc (count * sizeof (ip_address));
-  al->refcount  = 1;
+  al->count      = count;
+  al->faulty     = 0;
+  al->addresses  = xmalloc (count * sizeof (ip_address));
+  al->from_cache = 0;
+  al->refcount   = 1;
 
   for (i = 0; i < count; i++)
     {
@@ -290,10 +304,11 @@ static struct address_list *
 address_list_from_single (const ip_address *addr)
 {
   struct address_list *al = xmalloc (sizeof (struct address_list));
-  al->count     = 1;
-  al->faulty    = 0;
-  al->addresses = xmalloc (sizeof (ip_address));
-  al->refcount  = 1;
+  al->count      = 1;
+  al->faulty     = 0;
+  al->addresses  = xmalloc (sizeof (ip_address));
+  al->from_cache = 0;
+  al->refcount   = 1;
   memcpy (al->addresses, addr, sizeof (ip_address));
 
   return al;
@@ -319,203 +334,6 @@ address_list_release (struct address_list *al)
     }
 }
 \f
-/**
-  * 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;
-}
-\f
 /* Versions of gethostbyname and getaddrinfo that support timeout. */
 
 #ifndef ENABLE_IPV6
@@ -655,6 +473,17 @@ cache_host_lookup (const char *host, struct address_list *al)
 #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 *
 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));
          ++al->refcount;
+         al->from_cache = 1;
          return al;
        }
     }
index d2293dacfae079e88197e24bfb1f22cd322a1cf3..22e77038f02ba9f9cbf7f8aa359137b0261fb800 100644 (file)
@@ -84,12 +84,6 @@ typedef struct {
 #define ADDRESS_IPV4_IN_ADDR(x) ((x)->u.ipv4.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 */
 #define LH_SILENT    0x0001
 #define LH_PASSIVE   0x0002
@@ -100,10 +94,13 @@ typedef struct {
 struct address_list *lookup_host PARAMS ((const char *, int));
 char *herrmsg PARAMS ((int));
 
+void forget_host_lookup PARAMS ((const char *));
+
 void address_list_get_bounds PARAMS ((const struct address_list *,
                                      int *, int *));
-void address_list_copy_one PARAMS ((const struct address_list *, int,
-                                   ip_address *));
+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 *));
 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 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));
 
 #endif /* HOST_H */
index a3a40d4d7180861651bbce4d5b83513605f8abc7..88bb450d9d9450c143306c2e129a1f6f26e19d5d 100644 (file)
@@ -744,15 +744,10 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
 #endif /* HAVE_SSL */
       )
     {
-      struct address_list *al = lookup_host (conn->host, 0);
-      if (!al)
+      sock = connect_to_host (conn->host, conn->port);
+      if (sock == E_HOST)
        return HOSTERR;
-      set_connection_host_name (conn->host);
-      sock = connect_to_many (al, conn->port, 0);
-      set_connection_host_name (NULL);
-      address_list_release (al);
-
-      if (sock < 0)
+      else if (sock < 0)
        return CONNECT_ERROR (errno);
 
 #ifdef HAVE_SSL
index 0d006ecd6b897c5f44eadc15bbe7a8c9bd112cb7..96c061b99fe9c7ccf03a144af519c498b063b0e4 100644 (file)
@@ -111,8 +111,8 @@ so, delete this exception statement from your version.  */
 #ifdef __BEOS__
 # undef READ
 # undef WRITE
-# define READ(fd, buf, cnt) recv((fd), (buf), (cnt), 0)
-# define WRITE(fd, buf, cnt) send((fd), (buf), (cnt), 0)
+# define READ(fd, buf, cnt) recv ((fd), (buf), (cnt), 0)
+# define WRITE(fd, buf, cnt) send ((fd), (buf), (cnt), 0)
 #endif
 
 /* mswindows.h defines these.  */
@@ -126,10 +126,13 @@ so, delete this exception statement from your version.  */
 # define REALCLOSE(x) close (x)
 #endif
 
-#define CLOSE(x)                               \
-do {                                           \
-  REALCLOSE (x);                               \
-  DEBUGP (("Closing fd %d\n", x));             \
+#define CLOSE(x) do {                          \
+  int C_sock = (x);                            \
+  if (C_sock >= 0)                             \
+    {                                          \
+      REALCLOSE (C_sock);                      \
+      DEBUGP (("Closing fd %d\n", C_sock));    \
+    }                                          \
 } while (0)
 
 /* Define a large integral type useful for storing large sizes that