summaryrefslogtreecommitdiff
path: root/libjava
diff options
context:
space:
mode:
Diffstat (limited to 'libjava')
-rw-r--r--libjava/classpath/ChangeLog.gcj15
-rw-r--r--libjava/classpath/java/net/Inet4Address.java68
-rw-r--r--libjava/classpath/java/net/Inet6Address.java9
-rw-r--r--libjava/classpath/java/net/InetAddress.java377
-rw-r--r--libjava/classpath/java/net/ResolverCache.java269
-rw-r--r--libjava/classpath/java/net/SocketPermission.java161
6 files changed, 649 insertions, 250 deletions
diff --git a/libjava/classpath/ChangeLog.gcj b/libjava/classpath/ChangeLog.gcj
index fa1bbf37bf5..2f098d7e40c 100644
--- a/libjava/classpath/ChangeLog.gcj
+++ b/libjava/classpath/ChangeLog.gcj
@@ -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,
diff --git a/libjava/classpath/java/net/Inet4Address.java b/libjava/classpath/java/net/Inet4Address.java
index c80f1f175a2..28018a39c1c 100644
--- a/libjava/classpath/java/net/Inet4Address.java
+++ b/libjava/classpath/java/net/Inet4Address.java
@@ -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();
}
/**
diff --git a/libjava/classpath/java/net/Inet6Address.java b/libjava/classpath/java/net/Inet6Address.java
index 8d834a6fd28..2015fe1eb96 100644
--- a/libjava/classpath/java/net/Inet6Address.java
+++ b/libjava/classpath/java/net/Inet6Address.java
@@ -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;
diff --git a/libjava/classpath/java/net/InetAddress.java b/libjava/classpath/java/net/InetAddress.java
index ce65bc773b5..f6f97285fe6 100644
--- a/libjava/classpath/java/net/InetAddress.java
+++ b/libjava/classpath/java/net/InetAddress.java
@@ -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
index 00000000000..f8790666a0a
--- /dev/null
+++ b/libjava/classpath/java/net/ResolverCache.java
@@ -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;
+ }
+ }
+}
diff --git a/libjava/classpath/java/net/SocketPermission.java b/libjava/classpath/java/net/SocketPermission.java
index 97e93dcbb35..2d6343dc570 100644
--- a/libjava/classpath/java/net/SocketPermission.java
+++ b/libjava/classpath/java/net/SocketPermission.java
@@ -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;
}