]> sjero.net Git - wget/blobdiff - src/host.c
[svn] Move path_simplify to url.c.
[wget] / src / host.c
index c31cc05fa0cdfba7d8c6f3d883b1f49428332d30..ddc04445e0fe2d17909769a33b280a552802889b 100644 (file)
@@ -1,5 +1,5 @@
-/* Dealing with host names.
-   Copyright (C) 1995, 1996, 1997, 2000 Free Software Foundation, Inc.
+/* Host name resolution and matching.
+   Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
 
@@ -34,9 +34,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #else
 # include <sys/socket.h>
 # include <netinet/in.h>
-#ifndef __BEOS__
-# include <arpa/inet.h>
-#endif
+# ifndef __BEOS__
+#  include <arpa/inet.h>
+# endif
 # include <netdb.h>
 #endif /* WINDOWS */
 
@@ -59,31 +59,39 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 extern int errno;
 #endif
 
-#define IP4_ADDRESS_LENGTH 4
+#ifndef h_errno
+# ifndef __CYGWIN__
+extern int h_errno;
+# endif
+#endif
+
+/* An IPv4 address is simply a 4-byte quantity. */
+typedef unsigned char ipv4_address[4];
 
 /* Mapping between known hosts and to lists of their addresses. */
 
-struct hash_table *host_name_addresses_map;
+static struct hash_table *host_name_addresses_map;
 \f
 /* Lists of addresses.  This should eventually be extended to handle
    IPv6.  */
 
 struct address_list {
   int count;                   /* number of adrresses */
-  unsigned char *buffer;       /* buffer which holds all of them. */
+  ipv4_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. */
 };
 
-#define ADDR_LOCATION(al, index) ((al)->buffer + index * IP4_ADDRESS_LENGTH)
+/* Get the bounds of the address list.  */
 
-/* Return the number of addresses in the list. */
-
-int
-address_list_count (struct address_list *al)
+void
+address_list_get_bounds (struct address_list *al, int *start, int *end)
 {
-  return al->count;
+  *start = al->faulty;
+  *end   = al->count;
 }
 
 /* Copy address number INDEX to IP_STORE.  */
@@ -92,7 +100,8 @@ void
 address_list_copy_one (struct address_list *al, int index,
                       unsigned char *ip_store)
 {
-  memcpy (ip_store, ADDR_LOCATION (al, index), IP4_ADDRESS_LENGTH);
+  assert (index >= al->faulty && index < al->count);
+  memcpy (ip_store, al->addresses + index, sizeof (ipv4_address));
 }
 
 /* Check whether two address lists have all their IPs in common.  */
@@ -104,8 +113,28 @@ address_list_match_all (struct address_list *al1, struct address_list *al2)
     return 1;
   if (al1->count != al2->count)
     return 0;
-  return 0 == memcmp (al1->buffer, al2->buffer,
-                     al1->count * IP4_ADDRESS_LENGTH);
+  return 0 == memcmp (al1->addresses, al2->addresses,
+                     al1->count * sizeof (ipv4_address));
+}
+
+/* Mark the INDEXth element of AL as faulty, so that the next time
+   this address list is used, the faulty element will be skipped.  */
+
+void
+address_list_set_faulty (struct address_list *al, int index)
+{
+  /* We assume that the address list is traversed in order, so that a
+     "faulty" attempt is always preceded with all-faulty addresses,
+     and this is how Wget uses it.  */
+  assert (index == al->faulty);
+
+  ++al->faulty;
+  if (al->faulty >= al->count)
+    /* All addresses have been proven faulty.  Since there's not much
+       sense in returning the user an empty address list the next
+       time, we'll rather make them all clean, so that they can be
+       retried anew.  */
+    al->faulty = 0;
 }
 
 /* Create an address_list out of a NULL-terminated list of addresses,
@@ -121,12 +150,28 @@ address_list_new (char **h_addr_list)
   while (h_addr_list[count])
     ++count;
   assert (count > 0);
-  al->count    = count;
-  al->buffer   = xmalloc (count * IP4_ADDRESS_LENGTH);
-  al->refcount = 1;
+  al->count     = count;
+  al->faulty    = 0;
+  al->addresses = xmalloc (count * sizeof (ipv4_address));
+  al->refcount  = 1;
 
   for (i = 0; i < count; i++)
-    memcpy (ADDR_LOCATION (al, i), h_addr_list[i], IP4_ADDRESS_LENGTH);
+    memcpy (al->addresses + i, h_addr_list[i], sizeof (ipv4_address));
+
+  return al;
+}
+
+/* Like address_list_new, but initialized with only one address. */
+
+static struct address_list *
+address_list_new_one (const char *addr)
+{
+  struct address_list *al = xmalloc (sizeof (struct address_list));
+  al->count     = 1;
+  al->faulty    = 0;
+  al->addresses = xmalloc (sizeof (ipv4_address));
+  al->refcount  = 1;
+  memcpy (al->addresses, addr, sizeof (ipv4_address));
 
   return al;
 }
@@ -134,7 +179,7 @@ address_list_new (char **h_addr_list)
 static void
 address_list_delete (struct address_list *al)
 {
-  xfree (al->buffer);
+  xfree (al->addresses);
   xfree (al);
 }
 
@@ -154,7 +199,7 @@ address_list_release (struct address_list *al)
    #including the netinet stuff.  */
 
 char *
-pretty_print_address (const unsigned char *addr)
+pretty_print_address (const void *addr)
 {
   return inet_ntoa (*(struct in_addr *)addr);
 }
@@ -178,8 +223,7 @@ cache_host_lookup (const char *host, struct address_list *al)
       int i;
       debug_logprintf ("Caching %s =>", host);
       for (i = 0; i < al->count; i++)
-       debug_logprintf (" %s",
-                        pretty_print_address (ADDR_LOCATION (al, i)));
+       debug_logprintf (" %s", pretty_print_address (al->addresses + i));
       debug_logprintf ("\n");
     }
 #endif
@@ -197,9 +241,6 @@ lookup_host (const char *host, int silent)
   addr = (unsigned long)inet_addr (host);
   if ((int)addr != -1)
     {
-      unsigned char tmpstore[IP4_ADDRESS_LENGTH];
-      char *lst[] = { tmpstore, NULL };
-
       /* ADDR is defined to be in network byte order, which is what
         this returns, so we can just copy it to STORE_IP.  However,
         on big endian 64-bit architectures the value will be stored
@@ -207,12 +248,11 @@ lookup_host (const char *host, int silent)
         we copy the correct four bytes.  */
       int offset;
 #ifdef WORDS_BIGENDIAN
-      offset = sizeof (unsigned long) - IP4_ADDRESS_LENGTH;
+      offset = sizeof (unsigned long) - sizeof (ipv4_address);
 #else
       offset = 0;
 #endif
-      memcpy (tmpstore, (char *)&addr + offset, IP4_ADDRESS_LENGTH);
-      return address_list_new (lst);
+      return address_list_new_one ((char *)&addr + offset);
     }
 
   /* By now we know that the host name we got is not of the form
@@ -230,9 +270,7 @@ lookup_host (const char *host, int silent)
   if (!silent)
     logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
 
-  /* Look up the host using gethostbyname().  Note that we use
-     gethostbyname() rather than ngethostbyname(), because we already
-     know that the address is not numerical.  */
+  /* Look up the host using gethostbyname().  */
   hptr = gethostbyname (host);
   if (!hptr)
     {
@@ -244,6 +282,8 @@ lookup_host (const char *host, int silent)
   if (!silent)
     logprintf (LOG_VERBOSE, _("done.\n"));
 
+  /* Do all systems have h_addr_list, or is it a newer thing?  If the
+     latter, use address_list_new_one.  */
   al = address_list_new (hptr->h_addr_list);
 
   /* Cache the lookup information. */