OSDN Git Service

2006-09-20 Gary Benson <gbenson@redhat.com>
authorgary <gary@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 20 Sep 2006 07:53:18 +0000 (07:53 +0000)
committergary <gary@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 20 Sep 2006 07:53:18 +0000 (07:53 +0000)
* classpath/java/net/InetAddress.java: Updated to latest.
* classpath/java/net/Inet4Address.java: Likewise.
* classpath/java/net/Inet6Address.java: Likewise.
* classpath/java/net/ResolverCache.java: Likewise.
* classpath/java/net/SocketPermission.java: Likewise.

* classpath/java/net/Inet4Address.java
(AF_INET): Renamed to FAMILY.
(<init>, writeReplace): Reflect the above.
* classpath/java/net/Inet6Address.java
(AF_INET6): Renamed to FAMILY.
(<init>): Reflect the above.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@117074 138bc75d-0d04-0410-961f-82ee72b054a4

libjava/classpath/ChangeLog.gcj
libjava/classpath/java/net/Inet4Address.java
libjava/classpath/java/net/Inet6Address.java
libjava/classpath/java/net/InetAddress.java
libjava/classpath/java/net/ResolverCache.java [new file with mode: 0644]
libjava/classpath/java/net/SocketPermission.java

index fa1bbf3..2f098d7 100644 (file)
@@ -1,3 +1,18 @@
+2006-09-20  Gary Benson  <gbenson@redhat.com>
+
+       * classpath/java/net/InetAddress.java: Updated to latest.
+       * classpath/java/net/Inet4Address.java: Likewise.
+       * classpath/java/net/Inet6Address.java: Likewise.
+       * classpath/java/net/ResolverCache.java: Likewise.
+       * classpath/java/net/SocketPermission.java: Likewise.
+
+       * classpath/java/net/Inet4Address.java
+       (AF_INET): Renamed to FAMILY.
+       (<init>, writeReplace): Reflect the above.
+       * classpath/java/net/Inet6Address.java
+       (AF_INET6): Renamed to FAMILY.
+       (<init>): Reflect the above.
+
 2006-09-18  Tom Tromey  <tromey@redhat.com>
 
        * gnu/javax/net/ssl/provider/SSLSocket.java (isBound, isClosed,
index c80f1f1..28018a3 100644 (file)
@@ -1,5 +1,5 @@
 /* Inet4Address.java --
-   Copyright (C) 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -57,11 +57,16 @@ public final class Inet4Address extends InetAddress
   static final long serialVersionUID = 3286316764910316507L;
 
   /**
-   * needed for serialization
+   * The address family of these addresses (used for serialization).
+   */
+  private static final int FAMILY = 2; // AF_INET
+
+  /**
+   * Inet4Address objects are serialized as InetAddress objects.
    */
   private Object writeReplace() throws ObjectStreamException
   {
-    return new InetAddress(addr, hostName);
+    return new InetAddress(addr, hostName, FAMILY);
   }
   
   /**
@@ -74,7 +79,7 @@ public final class Inet4Address extends InetAddress
    */
   Inet4Address(byte[] addr, String host)
   {
-    super(addr, host);
+    super(addr, host, FAMILY);
   }
 
   /**
@@ -84,7 +89,7 @@ public final class Inet4Address extends InetAddress
    */
   public boolean isMulticastAddress()
   {
-    return super.isMulticastAddress();
+    return (addr[0] & 0xf0) == 0xe0;
   }
 
   /**
@@ -92,7 +97,7 @@ public final class Inet4Address extends InetAddress
    */
   public boolean isLoopbackAddress()
   {
-    return super.isLoopbackAddress();
+    return (addr[0] & 0xff) == 0x7f;
   }
 
   /**
@@ -102,7 +107,7 @@ public final class Inet4Address extends InetAddress
    */
   public boolean isAnyLocalAddress()
   {
-    return super.isAnyLocalAddress();
+    return equals(InetAddress.ANY_IF);
   }
 
   /**
@@ -112,7 +117,7 @@ public final class Inet4Address extends InetAddress
    */
   public boolean isLinkLocalAddress()
   {
-    return super.isLinkLocalAddress();
+    return false;
   }
 
   /**
@@ -122,7 +127,19 @@ public final class Inet4Address extends InetAddress
    */
   public boolean isSiteLocalAddress()
   {
-    return super.isSiteLocalAddress();
+    // 10.0.0.0/8
+    if ((addr[0] & 0xff) == 0x0a)
+      return true;
+
+    // 172.16.0.0/12
+    if ((addr[0] & 0xff) == 0xac && (addr[1] & 0xf0) == 0x10)
+      return true;
+
+    // 192.168.0.0/16
+    if ((addr[0] & 0xff) == 0xc0 && (addr[1] & 0xff) == 0xa8)
+      return true;
+
+    return false;
   }
 
   /**
@@ -132,7 +149,7 @@ public final class Inet4Address extends InetAddress
    */
   public boolean isMCGlobal()
   {
-    return super.isMCGlobal();
+    return false;
   }
 
   /**
@@ -142,7 +159,7 @@ public final class Inet4Address extends InetAddress
    */
   public boolean isMCNodeLocal()
   {
-    return super.isMCNodeLocal();
+    return false;
   }
 
   /**
@@ -152,7 +169,12 @@ public final class Inet4Address extends InetAddress
    */
   public boolean isMCLinkLocal()
   {
-    return super.isMCLinkLocal();
+    if (! isMulticastAddress())
+      return false;
+
+    return ((addr[0] & 0xff) == 0xe0
+           && (addr[1] & 0xff)  == 0x00
+           && (addr[2] & 0xff)  == 0x00);
   }
 
   /**
@@ -162,7 +184,7 @@ public final class Inet4Address extends InetAddress
    */
   public boolean isMCSiteLocal()
   {
-    return super.isMCSiteLocal();
+    return false;
   }
 
   /**
@@ -172,7 +194,7 @@ public final class Inet4Address extends InetAddress
    */
   public boolean isMCOrgLocal()
   {
-    return super.isMCOrgLocal();
+    return false;
   }
 
   /**
@@ -190,7 +212,23 @@ public final class Inet4Address extends InetAddress
    */
   public String getHostAddress()
   {
-    return super.getHostAddress();
+    StringBuffer sb = new StringBuffer(40);
+
+    int len = addr.length;
+    int i = 0;
+    
+    for ( ; ; )
+      {
+        sb.append(addr[i] & 0xff);
+        i++;
+       
+        if (i == len)
+          break;
+       
+        sb.append('.');
+      }
+
+    return sb.toString();
   }
 
   /**
index 8d834a6..2015fe1 100644 (file)
@@ -1,5 +1,5 @@
 /* Inet6Address.java --
-   Copyright (C) 2002, 2003, 2004  Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -93,6 +93,11 @@ public final class Inet6Address extends InetAddress
   private transient NetworkInterface nif; 
 
   /**
+   * The address family of these addresses (used for serialization).
+   */
+  private static final int FAMILY = 10; // AF_INET6
+
+  /**
    * Create an Inet6Address object
    *
    * @param addr The IP address
@@ -100,7 +105,7 @@ public final class Inet6Address extends InetAddress
    */
   Inet6Address(byte[] addr, String host)
   {
-    super(addr, host);
+    super(addr, host, FAMILY);
     // Super constructor clones the addr.  Get a reference to the clone.
     this.ipaddress = this.addr;
     ifname = null;
index ce65bc7..f6f9728 100644 (file)
@@ -1,5 +1,6 @@
 /* InetAddress.java -- Class to model an Internet address
-   Copyright (C) 1998, 1999, 2002, 2004, 2005  Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2002, 2004, 2005, 2006
+   Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -43,7 +44,6 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.ObjectStreamException;
 import java.io.Serializable;
-import java.util.StringTokenizer;
 
 /**
  * This class models an Internet address.  It does not have a public
@@ -57,6 +57,7 @@ import java.util.StringTokenizer;
  *
  * @author Aaron M. Renn (arenn@urbanophile.com)
  * @author Per Bothner
+ * @author Gary Benson (gbenson@redhat.com)
  *
  * @specnote This class is not final since JK 1.4
  */
@@ -65,37 +66,47 @@ public class InetAddress implements Serializable
   private static final long serialVersionUID = 3286316764910316507L;
 
   /**
-   * The special IP address INADDR_ANY.
-   */
-  private static InetAddress inaddr_any;
-
-  /**
    * Dummy InetAddress, used to bind socket to any (all) network interfaces.
    */
   static InetAddress ANY_IF;
-
+  static
+  {
+    byte[] addr;
+    try
+      {
+       addr = VMInetAddress.lookupInaddrAny();
+      }
+    catch (UnknownHostException e)
+      {
+       // Make one up and hope it works.
+       addr = new byte[] {0, 0, 0, 0};
+      }
+    try
+      {
+       ANY_IF = getByAddress(addr);
+      }
+    catch (UnknownHostException e)
+      {
+       throw new RuntimeException("should never happen", e);
+      }
+    ANY_IF.hostName = ANY_IF.getHostName();
+  }
+  
   /**
    * Stores static localhost address object.
    */
   static InetAddress LOCALHOST;
-
   static
   {
-    // precompute the ANY_IF address
     try
       {
-        ANY_IF = getInaddrAny();
-
-       byte[] ip_localhost = { 127, 0, 0, 1 };
-       LOCALHOST = new Inet4Address(ip_localhost, "localhost");
+       LOCALHOST = getByAddress("localhost", new byte[] {127, 0, 0, 1});
       }
-    catch (UnknownHostException uhe)
+    catch (UnknownHostException e)
       {
-        // Hmmm, make one up and hope that it works.
-        byte[] zeros = { 0, 0, 0, 0 };
-        ANY_IF = new Inet4Address(zeros, "0.0.0.0");
+       throw new RuntimeException("should never happen", e);
       }
-  }
+  }    
 
   /**
    * The Serialized Form specifies that an int 'address' is saved/restored.
@@ -115,28 +126,28 @@ public class InetAddress implements Serializable
   String hostName;
 
   /**
-   * The field 'family' seems to be the AF_ value.
-   * FIXME: Much of the code in the other java.net classes does not make
-   * use of this family field.  A better implementation would be to make
-   * use of getaddrinfo() and have other methods just check the family
-   * field rather than examining the length of the address each time.
+   * Needed for serialization.
    */
-  int family;
+  private int family;
 
   /**
-   * Initializes this object's addr instance variable from the passed in
-   * byte array.  Note that this constructor is protected and is called
-   * only by static methods in this class.
+   * Constructor.  Prior to the introduction of IPv6 support in 1.4,
+   * methods such as InetAddress.getByName() would return InetAddress
+   * objects.  From 1.4 such methods returned either Inet4Address or
+   * Inet6Address objects, but for compatibility Inet4Address objects
+   * are serialized as InetAddresses.  As such, there are only two
+   * places where it is appropriate to invoke this constructor: within
+   * subclasses constructors and within Inet4Address.writeReplace().
    *
    * @param ipaddr The IP number of this address as an array of bytes
    * @param hostname The hostname of this IP address.
+   * @param family The address family of this IP address.
    */
-  InetAddress(byte[] ipaddr, String hostname)
+  InetAddress(byte[] ipaddr, String hostname, int family)
   {
     addr = (null == ipaddr) ? null : (byte[]) ipaddr.clone();
     hostName = hostname;
-    
-    family = 2; /* AF_INET */
+    this.family = family;
   }
 
   /**
@@ -144,150 +155,144 @@ public class InetAddress implements Serializable
    * An address is multicast if the high four bits are "1110".  These are
    * also known as "Class D" addresses.
    *
+   * <p>This method cannot be abstract for backward compatibility reasons. By
+   * default it always throws {@link UnsupportedOperationException} unless
+   * overridden.</p>
+   * 
    * @return true if mulitcast, false if not
    *
    * @since 1.1
    */
   public boolean isMulticastAddress()
   {
-    // Mask against high order bits of 1110
-    if (addr.length == 4)
-      return (addr[0] & 0xf0) == 0xe0;
-
-    return false;
+    throw new UnsupportedOperationException();
   }
 
   /**
    * Utility routine to check if the InetAddress in a wildcard address
    *
+   * <p>This method cannot be abstract for backward compatibility reasons. By
+   * default it always throws {@link UnsupportedOperationException} unless
+   * overridden.</p>
+   * 
    * @since 1.4
    */
   public boolean isAnyLocalAddress()
   {
-    // This is the IPv4 implementation.
-    // Any class derived from InetAddress should override this.
-    return equals(ANY_IF);
+    throw new UnsupportedOperationException();
   }
 
   /**
    * Utility routine to check if the InetAddress is a loopback address
    *
+   * <p>This method cannot be abstract for backward compatibility reasons. By
+   * default it always throws {@link UnsupportedOperationException} unless
+   * overridden.</p>
+   * 
    * @since 1.4
    */
   public boolean isLoopbackAddress()
   {
-    // This is the IPv4 implementation.
-    // Any class derived from InetAddress should override this.
-    return (addr[0] & 0xff) == 0x7f;
+    throw new UnsupportedOperationException();
   }
 
   /**
    * Utility routine to check if InetAddress is a link local address
    *
+   * <p>This method cannot be abstract for backward compatibility reasons. By
+   * default it always throws {@link UnsupportedOperationException} unless
+   * overridden.</p>
+   * 
    * @since 1.4
    */
   public boolean isLinkLocalAddress()
   {
-    // This is the IPv4 implementation.
-    // Any class derived from InetAddress should override this.
-    // XXX: This seems to not exist with IPv4 addresses
-    return false;
+    throw new UnsupportedOperationException();
   }
 
   /**
    * Utility routine to check if InetAddress is a site local address
    *
+   * <p>This method cannot be abstract for backward compatibility reasons. By
+   * default it always throws {@link UnsupportedOperationException} unless
+   * overridden.</p>
+   * 
    * @since 1.4
    */
   public boolean isSiteLocalAddress()
   {
-    // This is the IPv4 implementation.
-    // Any class derived from InetAddress should override this.
-
-    // 10.0.0.0/8
-    if ((addr[0] & 0xff) == 0x0a)
-      return true;
-
-    // 172.16.0.0/12
-    if ((addr[0] & 0xff) == 0xac && (addr[1] & 0xf0) == 0x10)
-      return true;
-
-    // 192.168.0.0/16
-    if ((addr[0] & 0xff) == 0xc0 && (addr[1] & 0xff) == 0xa8)
-      return true;
-
-    // XXX: Do we need to check more addresses here ?
-    return false;
+    throw new UnsupportedOperationException();
   }
 
   /**
    * Utility routine to check if InetAddress is a global multicast address
    *
+   * <p>This method cannot be abstract for backward compatibility reasons. By
+   * default it always throws {@link UnsupportedOperationException} unless
+   * overridden.</p>
+   * 
    * @since 1.4
    */
   public boolean isMCGlobal()
   {
-    // This is the IPv4 implementation.
-    // Any class derived from InetAddress should override this.
-    // XXX: This seems to not exist with IPv4 addresses
-    return false;
+    throw new UnsupportedOperationException();
   }
 
   /**
    * Utility routine to check if InetAddress is a node local multicast address.
    *
+   * <p>This method cannot be abstract for backward compatibility reasons. By
+   * default it always throws {@link UnsupportedOperationException} unless
+   * overridden.</p>
+   * 
    * @since 1.4
    */
   public boolean isMCNodeLocal()
   {
-    // This is the IPv4 implementation.
-    // Any class derived from InetAddress should override this.
-    // XXX: This seems to not exist with IPv4 addresses
-    return false;
+    throw new UnsupportedOperationException();
   }
 
   /**
    * Utility routine to check if InetAddress is a link local multicast address.
    *
+   * <p>This method cannot be abstract for backward compatibility reasons. By
+   * default it always throws {@link UnsupportedOperationException} unless
+   * overridden.</p>
+   * 
    * @since 1.4
    */
   public boolean isMCLinkLocal()
   {
-    // This is the IPv4 implementation.
-    // Any class derived from InetAddress should override this.
-    if (! isMulticastAddress())
-      return false;
-
-    return ((addr[0] & 0xff) == 0xe0
-           && (addr[1] & 0xff)  == 0x00
-           && (addr[2] & 0xff)  == 0x00);
+    throw new UnsupportedOperationException();
   }
 
   /**
    * Utility routine to check if InetAddress is a site local multicast address.
    *
+   * <p>This method cannot be abstract for backward compatibility reasons. By
+   * default it always throws {@link UnsupportedOperationException} unless
+   * overridden.</p>
+   * 
    * @since 1.4
    */
   public boolean isMCSiteLocal()
   {
-    // This is the IPv4 implementation.
-    // Any class derived from InetAddress should override this.
-    // XXX: This seems to not exist with IPv4 addresses
-    return false;
+    throw new UnsupportedOperationException();
   }
 
   /**
    * Utility routine to check if InetAddress is a organization local
    * multicast address.
    *
+   * <p>This method cannot be abstract for backward compatibility reasons. By
+   * default it always throws {@link UnsupportedOperationException} unless
+   * overridden.</p>
+   * 
    * @since 1.4
    */
   public boolean isMCOrgLocal()
   {
-    // This is the IPv4 implementation.
-    // Any class derived from InetAddress should override this.
-    // XXX: This seems to not exist with IPv4 addresses
-    return false;
+    throw new UnsupportedOperationException();
   }
 
   /**
@@ -298,13 +303,20 @@ public class InetAddress implements Serializable
    */
   public String getHostName()
   {
-    if (hostName != null)
-      return hostName;
+    if (hostName == null)
+      hostName = getCanonicalHostName();
 
+    return hostName;
+  }
+
+  /**
+   * Returns the canonical hostname represented by this InetAddress
+   */
+  String internalGetCanonicalHostName()
+  {
     try
       {
-       hostName = VMInetAddress.getHostByAddr(addr);
-       return hostName;
+       return ResolverCache.getHostByAddr(addr);
       }
     catch (UnknownHostException e)
       {
@@ -319,12 +331,14 @@ public class InetAddress implements Serializable
    */
   public String getCanonicalHostName()
   {
+    String hostname = internalGetCanonicalHostName();
+
     SecurityManager sm = System.getSecurityManager();
     if (sm != null)
       {
         try
          {
-            sm.checkConnect(hostName, -1);
+            sm.checkConnect(hostname, -1);
          }
        catch (SecurityException e)
          {
@@ -332,16 +346,7 @@ public class InetAddress implements Serializable
          }
       }
 
-    // Try to find the FDQN now
-    InetAddress address;
-    byte[] ipaddr = getAddress();
-
-    if (ipaddr.length == 16)
-      address = new Inet6Address(getAddress(), null);
-    else
-      address = new Inet4Address(getAddress(), null);
-
-    return address.getHostName();
+    return hostname;
   }
 
   /**
@@ -357,32 +362,19 @@ public class InetAddress implements Serializable
   }
 
   /**
-   * Returns the IP address of this object as a String.  The address is in
-   * the dotted octet notation, for example, "127.0.0.1".
+   * Returns the IP address of this object as a String.
    *
+   * <p>This method cannot be abstract for backward compatibility reasons. By
+   * default it always throws {@link UnsupportedOperationException} unless
+   * overridden.</p>
+   * 
    * @return The IP address of this object in String form
    *
    * @since 1.0.2
    */
   public String getHostAddress()
   {
-    StringBuffer sb = new StringBuffer(40);
-
-    int len = addr.length;
-    int i = 0;
-    
-    for ( ; ; )
-      {
-        sb.append(addr[i] & 0xff);
-        i++;
-       
-        if (i == len)
-          break;
-       
-        sb.append('.');
-      }
-
-    return sb.toString();
+    throw new UnsupportedOperationException();
   }
 
   /**
@@ -488,48 +480,50 @@ public class InetAddress implements Serializable
       return new Inet4Address(addr, host);
 
     if (addr.length == 16)
-      return new Inet6Address(addr, host);
+      {
+       for (int i = 0; i < 12; i++)
+         {
+           if (addr[i] != (i < 10 ? 0 : (byte) 0xFF))
+             return new Inet6Address(addr, host);
+         }
+         
+       byte[] ip4addr = new byte[4];
+       ip4addr[0] = addr[12];
+       ip4addr[1] = addr[13];
+       ip4addr[2] = addr[14];
+       ip4addr[3] = addr[15];
+       return new Inet4Address(ip4addr, host);
+      }
 
     throw new UnknownHostException("IP address has illegal length");
   }
 
   /**
-   * If hostname is a valid numeric IP address, return the numeric address.
-   * Otherwise, return null.
+   * Returns an InetAddress object representing the IP address of
+   * the given literal IP address in dotted decimal format such as
+   * "127.0.0.1".  This is used by SocketPermission.setHostPort()
+   * to parse literal IP addresses without performing a DNS lookup.
+   *
+   * @param literal The literal IP address to create the InetAddress
+   * object from
    *
-   * @param hostname the name of the host
+   * @return The address of the host as an InetAddress object, or
+   * null if the IP address is invalid.
    */
-  private static byte[] aton(String hostname)
+  static InetAddress getByLiteral(String literal)
   {
-    StringTokenizer st = new StringTokenizer(hostname, ".");
-
-    if (st.countTokens() == 4)
+    byte[] address = VMInetAddress.aton(literal);
+    if (address == null)
+      return null;
+    
+    try
       {
-       int index;
-       byte[] address = new byte[4];
-
-       for (index = 0; index < 4; index++)
-         {
-           try
-             {
-               short n = Short.parseShort(st.nextToken());
-
-               if ((n < 0) || (n > 255))
-                 break;
-
-               address[index] = (byte) n;
-             }
-           catch (NumberFormatException e)
-             {
-               break;
-             }
-         }
-
-       if (index == 4)
-         return address;
+       return getByAddress(address);
+      }
+    catch (UnknownHostException e)
+      {
+       throw new RuntimeException("should never happen", e);
       }
-
-    return null;
   }
 
   /**
@@ -577,63 +571,34 @@ public class InetAddress implements Serializable
   public static InetAddress[] getAllByName(String hostname)
     throws UnknownHostException
   {
-    SecurityManager s = System.getSecurityManager();
-    if (s != null)
-      s.checkConnect(hostname, -1);
-
-    InetAddress[] addresses;
-
-    if (hostname != null)
-      hostname = hostname.trim();
+    // If null or the empty string is supplied, the loopback address
+    // is returned.
+    if (hostname == null || hostname.length() == 0)
+      return new InetAddress[] {LOCALHOST};
 
-    // Default to current host if necessary
-    if (hostname == null || hostname.equals(""))
-      {
-       addresses = new InetAddress[1];
-       addresses[0] = LOCALHOST;
-       return addresses;
-      }
+    // Check if hostname is an IP address
+    InetAddress address = getByLiteral(hostname);
+    if (address != null)
+      return new InetAddress[] {address};
 
-    // Not in cache, try the lookup
-    byte[][] iplist = VMInetAddress.getHostByName(hostname);
+    // Perform security check before resolving
+    SecurityManager sm = System.getSecurityManager();
+    if (sm != null)
+      sm.checkConnect(hostname, -1);
 
+    // Resolve the hostname
+    byte[][] iplist = ResolverCache.getHostByName(hostname);
     if (iplist.length == 0)
       throw new UnknownHostException(hostname);
 
-    addresses = new InetAddress[iplist.length];
-
+    InetAddress[] addresses = new InetAddress[iplist.length];
     for (int i = 0; i < iplist.length; i++)
-      {
-       if (iplist[i].length != 4)
-         throw new UnknownHostException(hostname);
-
-       addresses[i] = new Inet4Address(iplist[i], hostname);
-      }
+      addresses[i] = getByAddress(hostname, iplist[i]);
 
     return addresses;
   }
 
   /**
-   * Returns the special address INADDR_ANY used for binding to a local
-   * port on all IP addresses hosted by a the local host.
-   *
-   * @return An InetAddress object representing INDADDR_ANY
-   *
-   * @exception UnknownHostException If an error occurs
-   */
-  static InetAddress getInaddrAny() throws UnknownHostException
-  {
-    if (inaddr_any == null)
-      {
-       byte[] tmp = VMInetAddress.lookupInaddrAny();
-       inaddr_any = new Inet4Address(tmp, null);
-       inaddr_any.hostName = inaddr_any.getHostName();
-      }
-
-    return inaddr_any;
-  }
-
-  /**
    * Returns an InetAddress object representing the address of the current
    * host.
    *
@@ -645,11 +610,19 @@ public class InetAddress implements Serializable
   public static InetAddress getLocalHost() throws UnknownHostException
   {
     String hostname = VMInetAddress.getLocalHostname();
-    return getByName(hostname);
+    try
+      {
+       return getByName(hostname);
+      }
+    catch (SecurityException e)
+      {
+       return LOCALHOST;
+      }
   }
 
-  /*
-   * Needed for serialization
+  /**
+   * Inet4Address objects are serialized as InetAddress objects.
+   * This deserializes them back into Inet4Address objects.
    */
   private Object readResolve() throws ObjectStreamException
   {
@@ -665,8 +638,6 @@ public class InetAddress implements Serializable
 
     for (int i = 2; i >= 0; --i)
       addr[i] = (byte) (address >>= 8);
-
-    family = 2; /* AF_INET  */
   }
 
   private void writeObject(ObjectOutputStream oos) throws IOException
diff --git a/libjava/classpath/java/net/ResolverCache.java b/libjava/classpath/java/net/ResolverCache.java
new file mode 100644 (file)
index 0000000..f879066
--- /dev/null
@@ -0,0 +1,269 @@
+/* ResolverCache.java -- A cache of resolver lookups for InetAddress.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.net;
+
+import java.security.Security;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * This class provides a cache of name service resolutions.  By
+ * default successful resolutions are cached forever to guard
+ * against DNS spoofing attacks and failed resolutions are cached
+ * for 10 seconds to improve performance.  The length of time that
+ * results remain in the cache is determined by the following
+ * security properties:
+ * <dl>
+ *   <dt><code>networkaddress.cache.ttl</code></dt>
+ *   <dd>
+ *     This property specifies the length of time in seconds that
+ *     successful resolutions remain in the cache.  The default is
+ *     -1, indicating to cache forever.
+ *   </dd>
+ *   <dt><code>networkaddress.cache.negative.ttl</code></dt>
+ *   <dd>
+ *     This property specifies the length of time in seconds that
+ *     unsuccessful resolutions remain in the cache.  The default
+ *     is 10, indicating to cache for 10 seconds.
+ *   </dd>
+ * In both cases, a value of -1 indicates to cache forever and a
+ * value of 0 indicates not to cache.
+ *
+ * @author Gary Benson (gbenson@redhat.com)
+ */
+class ResolverCache
+{
+  /**
+   * The time in seconds for which successful lookups are cached.
+   */
+  private static final int POSITIVE_TTL =
+    getTTL("networkaddress.cache.ttl", -1);
+
+  /**
+   * The time in seconds for which unsuccessful lookups are cached.
+   */
+  private static final int NEGATIVE_TTL =
+    getTTL("networkaddress.cache.negative.ttl", 10);
+
+  /**
+   * Helper function to set the TTLs.
+   */
+  private static int getTTL(String propName, int defaultValue)
+  {
+    String propValue = Security.getProperty(propName);
+    if (propValue == null)
+      return defaultValue;
+
+    return Integer.parseInt(propValue);
+  }
+
+  /**
+   * The cache itself.
+   */
+  private static HashMap cache = new HashMap();
+
+  /**
+   * List of entries which may expire.
+   */
+  private static LinkedList killqueue = new LinkedList();
+
+  /**
+   * Return the hostname for the specified IP address.
+   *
+   * @param ip The IP address as a byte array
+   *
+   * @return The hostname
+   *
+   * @exception UnknownHostException If the reverse lookup fails
+   */
+  public static String getHostByAddr(byte[] addr) throws UnknownHostException
+  {
+    Object key = makeHashableAddress(addr);
+    Entry entry = (Entry) get(key);
+    if (entry != null)
+      {
+       if (entry.value == null)
+         throw new UnknownHostException();
+       return (String) entry.value;
+      }
+
+    try
+      {
+       String hostname = VMInetAddress.getHostByAddr(addr);
+       put(new Entry(key, hostname));
+       return hostname;
+      }
+    catch (UnknownHostException e)
+      {
+       put(new Entry(key, null));
+       throw e;
+      }
+  }
+
+  /**
+   * Return a list of all IP addresses for the specified hostname.
+   *
+   * @param hostname The hostname
+   *
+   * @return An list of IP addresses as byte arrays
+   *
+   * @exception UnknownHostException If the lookup fails
+   */
+  public static byte[][] getHostByName(String hostname)
+    throws UnknownHostException
+  {
+    Entry entry = (Entry) get(hostname);
+    if (entry != null)
+      {
+       if (entry.value == null)
+         throw new UnknownHostException();
+       return (byte[][]) entry.value;
+      }
+
+    try
+      {
+       byte[][] addrs = VMInetAddress.getHostByName(hostname);
+       put(new Entry(hostname, addrs));
+       return addrs;
+      }
+    catch (UnknownHostException e)
+      {
+       put(new Entry(hostname, null));
+       throw e;
+      }
+  }
+
+  /**
+   * Convert an IP address expressed as a byte array into something
+   * we can use as a hashtable key.
+   */
+  private static Object makeHashableAddress(byte[] addr)
+  {
+    char[] chars = new char[addr.length];
+    for (int i = 0; i < addr.length; i++)
+      chars[i] = (char) addr[i];
+    return new String(chars);
+  }
+
+  /**
+   * Return the entry in the cache associated with the supplied key,
+   * or <code>null</code> if the cache does not contain an entry
+   * associated with this key.
+   */
+  private static synchronized Entry get(Object key)
+  {
+    reap();
+    return (Entry) cache.get(key);
+  }
+
+  /**
+   * Insert the supplied entry into the cache.
+   */
+  private static synchronized void put(Entry entry)
+  {
+    reap();
+    if (entry.expires != 0)
+      {
+       if (entry.expires != -1)
+         killqueue.add(entry);
+       cache.put(entry.key, entry);
+      }
+  }
+
+  /**
+   * Clear expired entries.  This method is not synchronized, so
+   * it must only be called by methods that are.
+   */
+  private static void reap()
+  {
+    if (!killqueue.isEmpty())
+      {
+       long now = System.currentTimeMillis();
+
+       Iterator iter = killqueue.iterator();
+       while (iter.hasNext())
+         {
+           Entry entry = (Entry) iter.next();
+           if (entry.expires > now)
+             break;
+           cache.remove(entry.key);
+           iter.remove();
+         }
+      }
+  }
+  
+  /**
+   * An entry in the cache.
+   */
+  private static class Entry
+  {
+    /**
+     * The key by which this entry is referenced.
+     */
+    public final Object key;
+
+    /**
+     * The entry itself.  A null value indicates a failed lookup.
+     */
+    public final Object value;
+    
+    /**
+     * The time when this cache entry expires.  If set to -1 then
+     * this entry will never expire.  If set to 0 then this entry
+     * expires immediately and will not be inserted into the cache.
+     */
+    public final long expires;
+
+    /**
+     * Constructor.
+     */
+    public Entry(Object key, Object value)
+    {
+      this.key = key;
+      this.value = value;
+
+      int ttl = value != null ? POSITIVE_TTL : NEGATIVE_TTL;
+      if (ttl < 1)
+       expires = ttl;
+      else
+       expires = System.currentTimeMillis() + ttl * 1000;
+    }
+  }
+}
index 97e93dc..2d6343d 100644 (file)
@@ -117,11 +117,18 @@ public final class SocketPermission extends Permission implements Serializable
   static final long serialVersionUID = -7204263841984476862L;
 
   /**
-   * A hostname (possibly wildcarded) or IP address (IPv4 or IPv6).
+   * A hostname (possibly wildcarded).  Will be set if and only if
+   * this object was initialized with a hostname.
    */
-  private transient String host;
+  private transient String hostname = null;
 
   /**
+   * An IP address (IPv4 or IPv6).  Will be set if and only if this
+   * object was initialized with a single literal IP address.
+   */  
+  private transient InetAddress address = null;
+  
+  /**
    * A range of ports.
    */
   private transient int minport;
@@ -225,7 +232,7 @@ public final class SocketPermission extends Permission implements Serializable
   private void setHostPort(String hostport)
   {
     // Split into host and ports
-    String ports;
+    String host, ports;
     if (hostport.charAt(0) == '[')
       {
        // host is a bracketed IPv6 address
@@ -234,6 +241,10 @@ public final class SocketPermission extends Permission implements Serializable
          throw new IllegalArgumentException("Unmatched '['");
        host = hostport.substring(1, end);
 
+       address = InetAddress.getByLiteral(host);
+       if (address == null)
+         throw new IllegalArgumentException("Bad IPv6 address");
+
        if (end == hostport.length() - 1)
          ports = "";
        else if (hostport.charAt(end + 1) == ':')
@@ -255,6 +266,15 @@ public final class SocketPermission extends Permission implements Serializable
            host = hostport.substring(0, sep);
            ports = hostport.substring(sep + 1);
          }
+
+       address = InetAddress.getByLiteral(host);
+       if (address == null)
+         {
+           if (host.lastIndexOf('*') > 0)
+             throw new IllegalArgumentException("Bad hostname");
+
+           hostname = host;
+         }
       }
 
     // Parse and validate the ports
@@ -362,10 +382,25 @@ public final class SocketPermission extends Permission implements Serializable
     else
       return false;
 
-    return p.actionmask == actionmask &&
-      p.minport == minport &&
-      p.maxport == maxport &&
-      p.host.equals(host);
+    if (p.actionmask != actionmask ||
+       p.minport != minport ||
+       p.maxport != maxport)
+      return false;
+
+    if (address != null)
+      {
+       if (p.address == null)
+         return false;
+       else
+         return p.address.equals(address);
+      }
+    else
+      {
+       if (p.hostname == null)
+         return false;
+       else
+         return p.hostname.equals(hostname);
+      }
   }
 
   /**
@@ -376,7 +411,12 @@ public final class SocketPermission extends Permission implements Serializable
    */
   public int hashCode()
   {
-    return actionmask + minport + maxport + host.hashCode();
+    int code = actionmask + minport + maxport;
+    if (address != null)
+      code += address.hashCode();
+    else
+      code += hostname.hashCode();
+    return code;
   }
 
   /**
@@ -416,6 +456,44 @@ public final class SocketPermission extends Permission implements Serializable
   }
 
   /**
+   * Returns an array of all IP addresses represented by this object.
+   */
+  private InetAddress[] getAddresses()
+  {
+    if (address != null)
+      return new InetAddress[] {address};
+
+    try
+      {
+       return InetAddress.getAllByName(hostname);
+      }
+    catch (UnknownHostException e)
+      {
+       return new InetAddress[0];
+      }
+  }
+
+  /**
+   * Returns the canonical hostname represented by this object,
+   * or null if this object represents a wildcarded domain.
+   */
+  private String getCanonicalHostName()
+  {
+    if (address != null)
+      return address.internalGetCanonicalHostName();
+    if (hostname.charAt(0) == '*')
+      return null;
+    try
+      {
+       return InetAddress.getByName(hostname).internalGetCanonicalHostName();
+      }
+    catch (UnknownHostException e)
+      {
+       return null;
+      }
+  }
+  
+  /**
    * Returns true if the permission object passed it is implied by the
    * this permission.  This will be true if:
    * 
@@ -450,6 +528,11 @@ public final class SocketPermission extends Permission implements Serializable
     else
       return false;
 
+    // If p was initialised with an empty hostname then we do not
+    // imply it. This is not part of the spec, but it seems necessary.
+    if (p.hostname != null && p.hostname.length() == 0)
+      return false;
+    
     // Next check the actions
     if ((p.actionmask & actionmask) != p.actionmask)
        return false;
@@ -459,36 +542,54 @@ public final class SocketPermission extends Permission implements Serializable
       return false;
 
     // Finally check the hosts
-    if (host.equals(p.host))
-      return true;
+    String p_canon = null;
 
-    // Try the canonical names
-    String ourcanonical = null;
-    String theircanonical = null;
-    try
+    // Return true if this object was initialized with a single
+    // IP address which one of p's IP addresses is equal to.
+    if (address != null)
       {
-       ourcanonical = InetAddress.getByName(host).getHostName();
-       theircanonical = InetAddress.getByName(p.host).getHostName();
+       InetAddress[] addrs = p.getAddresses();
+       for (int i = 0; i < addrs.length; i++)
+         {
+           if (address.equals(addrs[i]))
+             return true;
+         }
       }
-    catch (UnknownHostException e)
+
+    // Return true if this object is a wildcarded domain that
+    // p's canonical name matches.
+    if (hostname != null && hostname.charAt(0) == '*')
       {
-       // Who didn't resolve?  Just assume current address is canonical enough
-       // Is this ok to do?
-       if (ourcanonical == null)
-         ourcanonical = host;
-       if (theircanonical == null)
-         theircanonical = p.host;
+       p_canon = p.getCanonicalHostName();
+       if (p_canon != null && p_canon.endsWith(hostname.substring(1)))
+         return true;
+       
       }
 
-    if (ourcanonical.equals(theircanonical))
-      return true;
+    // Return true if this one of this object's IP addresses
+    // is equal to one of p's.
+    if (address == null)
+      {
+       InetAddress[] addrs = p.getAddresses();
+       InetAddress[] p_addrs = p.getAddresses();
+
+       for (int i = 0; i < addrs.length; i++)
+         {
+           for (int j = 0; j < p_addrs.length; j++)
+             {
+               if (addrs[i].equals(p_addrs[j]))
+                 return true;
+             }
+         }
+      }
 
-    // Well, last chance.  Try for a wildcard
-    if (host.indexOf("*.") != -1)
+    // Return true if this object's canonical name equals p's.
+    String canon = getCanonicalHostName();
+    if (canon != null)
       {
-       String wild_domain =
-         host.substring(host.indexOf("*" + 1));
-       if (theircanonical.endsWith(wild_domain))
+       if (p_canon == null)
+         p_canon = p.getCanonicalHostName();
+       if (p_canon != null && canon.equals(p_canon))
          return true;
       }