Hi all,

This commit merges a bunch of funky stuff from GCJ's InetAddress
(including all the fixes I've been working on over the past week
or so) and adds a bunch of other stuff I noticed while merging.
Particular hilights are that "raw" InetAddress objects no longer
exist anywhere (only Inet4Address and Inet6Address objects are
ever created now) and that a couple of excessive security checks
were relaxed.

Cheers,
Gary
Index: ChangeLog
===================================================================
RCS file: /cvsroot/classpath/classpath/ChangeLog,v
retrieving revision 1.8513
diff -u -r1.8513 ChangeLog
--- ChangeLog   7 Sep 2006 11:42:13 -0000       1.8513
+++ ChangeLog   8 Sep 2006 08:23:15 -0000
@@ -1,3 +1,31 @@
+2006-09-08  Gary Benson  <[EMAIL PROTECTED]>
+
+       * java/net/InetAddress.java
+       (inaddr_any): Removed.
+       (ANY_IF, LOCALHOST): Create using getByAddress.
+       (<init>): Updated javadoc.
+       (getHostName): Cache hostname even if the lookup failed.
+       (getByAddress): Create Inet4Address objects when passed
+       IPv4-mapped IPv6 addresses.
+       (aton): Removed.
+       (getAllByName): Create address objects using getByAddress.
+       Do not perform security checks unless actually required.
+       Do not strip whitespace from the hostname.
+       (getInaddrAny): Removed.
+       (getLocalHost): Return the loopback address if getByName
+       throws a SecurityException.
+       (readResolve): Updated javadoc.
+       * vm/reference/java/net/VMInetAddress.java (aton): Declared.
+       * include/java_net_VMInetAddress.h
+       (Java_java_net_VMInetAddress_aton): Likewise.
+       * native/jni/java-net/java_net_VMInetAddress.c
+       (Java_java_net_VMInetAddress_aton): New method.
+       * native/jni/native-lib/cpnet.h (cpnet_aton): Declared.
+       * native/jni/native-lib/cpnet.c (cpnet_aton): New method.
+       * configure.ac (AC_CHECK_FUNCS): Checks for cpnet_aton.
+       * java/net/Inet4Address.java (writeReplace): Updated javadoc.
+       * NEWS: Added note about updated VM interface.
+
 2006-09-07  David Gilbert  <[EMAIL PROTECTED]>
 
        * javax/swing/plaf/basic/BasicInternalFrameUI.java
Index: java/net/InetAddress.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/net/InetAddress.java,v
retrieving revision 1.46
diff -u -r1.46 InetAddress.java
--- java/net/InetAddress.java   6 Feb 2006 12:50:03 -0000       1.46
+++ java/net/InetAddress.java   8 Sep 2006 08:23:19 -0000
@@ -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.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 @@
  *
  * @author Aaron M. Renn ([EMAIL PROTECTED])
  * @author Per Bothner
+ * @author Gary Benson ([EMAIL PROTECTED])
  *
  * @specnote This class is not final since JK 1.4
  */
@@ -65,37 +66,47 @@
   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.
@@ -124,9 +135,13 @@
   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.
@@ -304,12 +319,13 @@
     try
       {
        hostName = VMInetAddress.getHostByAddr(addr);
-       return hostName;
       }
     catch (UnknownHostException e)
       {
-       return getHostAddress();
+       hostName = getHostAddress();
       }
+
+    return hostName;
   }
 
   /**
@@ -488,48 +504,22 @@
       return new Inet4Address(addr, host);
 
     if (addr.length == 16)
-      return new Inet6Address(addr, host);
-
-    throw new UnknownHostException("IP address has illegal length");
-  }
-
-  /**
-   * If hostname is a valid numeric IP address, return the numeric address.
-   * Otherwise, return null.
-   *
-   * @param hostname the name of the host
-   */
-  private static byte[] aton(String hostname)
-  {
-    StringTokenizer st = new StringTokenizer(hostname, ".");
-
-    if (st.countTokens() == 4)
       {
-       int index;
-       byte[] address = new byte[4];
-
-       for (index = 0; index < 4; index++)
+       for (int i = 0; i < 12; i++)
          {
-           try
-             {
-               short n = Short.parseShort(st.nextToken());
-
-               if ((n < 0) || (n > 255))
-                 break;
-
-               address[index] = (byte) n;
-             }
-           catch (NumberFormatException e)
-             {
-               break;
-             }
+           if (addr[i] != (i < 10 ? 0 : (byte) 0xFF))
+             return new Inet6Address(addr, host);
          }
-
-       if (index == 4)
-         return address;
+         
+       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);
       }
 
-    return null;
+    throw new UnknownHostException("IP address has illegal length");
   }
 
   /**
@@ -577,63 +567,34 @@
   public static InetAddress[] getAllByName(String hostname)
     throws UnknownHostException
   {
-    SecurityManager s = System.getSecurityManager();
-    if (s != null)
-      s.checkConnect(hostname, -1);
+    // If null or the empty string is supplied, the loopback address
+    // is returned.
+    if (hostname == null || hostname.length() == 0)
+      return new InetAddress[] {LOCALHOST};
+
+    // Check if hostname is an IP address
+    byte[] address = VMInetAddress.aton(hostname);
+    if (address != null)
+      return new InetAddress[] {getByAddress(address)};
 
-    InetAddress[] addresses;
-
-    if (hostname != null)
-      hostname = hostname.trim();
-
-    // Default to current host if necessary
-    if (hostname == null || hostname.equals(""))
-      {
-       addresses = new InetAddress[1];
-       addresses[0] = LOCALHOST;
-       return addresses;
-      }
+    // Perform security check before resolving
+    SecurityManager sm = System.getSecurityManager();
+    if (sm != null)
+      sm.checkConnect(hostname, -1);
 
-    // Not in cache, try the lookup
+    // Resolve the hostname
     byte[][] iplist = VMInetAddress.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 +606,19 @@
   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
   {
Index: vm/reference/java/net/VMInetAddress.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/vm/reference/java/net/VMInetAddress.java,v
retrieving revision 1.3
diff -u -r1.3 VMInetAddress.java
--- vm/reference/java/net/VMInetAddress.java    2 Mar 2006 00:36:44 -0000       
1.3
+++ vm/reference/java/net/VMInetAddress.java    8 Sep 2006 08:23:21 -0000
@@ -84,4 +84,14 @@
    */
   public static native byte[][] getHostByName(String hostname)
     throws UnknownHostException;
+
+  /**
+   * Return the IP address represented by a literal address.
+   * Will return null if the literal address is not valid.
+   *
+   * @param address the name of the host
+   *
+   * @return The IP address as a byte array
+   */
+  public static native byte[] aton(String address);
 }
Index: include/java_net_VMInetAddress.h
===================================================================
RCS file: /cvsroot/classpath/classpath/include/java_net_VMInetAddress.h,v
retrieving revision 1.1
diff -u -r1.1 java_net_VMInetAddress.h
--- include/java_net_VMInetAddress.h    11 Apr 2005 18:58:38 -0000      1.1
+++ include/java_net_VMInetAddress.h    8 Sep 2006 08:23:23 -0000
@@ -14,6 +14,7 @@
 JNIEXPORT jbyteArray JNICALL Java_java_net_VMInetAddress_lookupInaddrAny 
(JNIEnv *env, jclass);
 JNIEXPORT jstring JNICALL Java_java_net_VMInetAddress_getHostByAddr (JNIEnv 
*env, jclass, jbyteArray);
 JNIEXPORT jobjectArray JNICALL Java_java_net_VMInetAddress_getHostByName 
(JNIEnv *env, jclass, jstring);
+JNIEXPORT jbyteArray JNICALL Java_java_net_VMInetAddress_aton (JNIEnv *env, 
jclass, jstring);
 
 #ifdef __cplusplus
 }
Index: native/jni/java-net/java_net_VMInetAddress.c
===================================================================
RCS file: 
/cvsroot/classpath/classpath/native/jni/java-net/java_net_VMInetAddress.c,v
retrieving revision 1.8
diff -u -r1.8 java_net_VMInetAddress.c
--- native/jni/java-net/java_net_VMInetAddress.c        21 Aug 2006 23:34:45 
-0000      1.8
+++ native/jni/java-net/java_net_VMInetAddress.c        8 Sep 2006 08:23:26 
-0000
@@ -299,4 +299,91 @@
 #endif /* not WITHOUT_NETWORK */
 }
 
+/*************************************************************************/
+
+/*
+ * Return the IP address represented by a literal address.
+ * Will return null if the literal address is not valid.
+ */
+JNIEXPORT jbyteArray JNICALL
+Java_java_net_VMInetAddress_aton (JNIEnv *env,
+                                 jclass class
+                                 __attribute__ ((__unused__)),
+                                 jstring host)
+{
+#ifndef WITHOUT_NETWORK
+  const char *hostname;
+  cpnet_address *address;
+  int result;
+  jbyte *octets;
+  jbyteArray ret_octets;
+
+  hostname = (*env)->GetStringUTFChars (env, host, 0);
+  if (!hostname)
+    {
+      JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Null hostname");
+      return (jbyteArray) NULL;
+    }
+
+  result = cpnet_aton (env, hostname, &address);
+  if (result != CPNATIVE_OK)
+    {
+      JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Internal Error");
+      if (address)
+       cpnet_freeAddress (env, address);
+      return (jbyteArray) NULL;
+    }
+  if (!address)
+    return (jbyteArray) NULL;
+
+  if (cpnet_isIPV6Address (address))
+    {
+      ret_octets = (jbyteArray) (*env)->NewByteArray (env, 16);
+
+      if (!ret_octets)
+       {
+         JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Internal Error");
+         cpnet_freeAddress (env, address);
+         return (jbyteArray) NULL;
+       }
+         
+      octets = (*env)->GetByteArrayElements (env, ret_octets, 0);
+
+      cpnet_IPV6AddressToBytes (address, octets);
+
+      (*env)->ReleaseByteArrayElements (env, ret_octets, octets, 0);
+    }
+  else if (cpnet_isIPV4Address (address))
+    {
+      ret_octets = (jbyteArray) (*env)->NewByteArray (env, 4);
+
+      if (!ret_octets)
+       {
+         JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Internal Error");
+         cpnet_freeAddress (env, address);
+         return (jbyteArray) NULL;
+       }
+         
+      octets = (*env)->GetByteArrayElements (env, ret_octets, 0);
+
+      cpnet_IPV4AddressToBytes (address, octets);
+
+      (*env)->ReleaseByteArrayElements (env, ret_octets, octets, 0);
+    }
+  else
+    {
+      JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Internal Error");
+      cpnet_freeAddress (env, address);
+      return (jbyteArray) NULL;
+    }
+
+  cpnet_freeAddress (env, address);
+
+  return (ret_octets);
+  
+#else /* not WITHOUT_NETWORK */
+  return (jbyteArray) NULL;
+#endif /* not WITHOUT_NETWORK */
+}
+
 /* end of file */
Index: native/jni/native-lib/cpnet.h
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/native-lib/cpnet.h,v
retrieving revision 1.2
diff -u -r1.2 cpnet.h
--- native/jni/native-lib/cpnet.h       21 Aug 2006 23:34:46 -0000      1.2
+++ native/jni/native-lib/cpnet.h       8 Sep 2006 08:23:29 -0000
@@ -94,6 +94,7 @@
 JNIEXPORT jint cpnet_getHostname (JNIEnv *env, char *hostname, jint 
hostname_len);
 JNIEXPORT jint cpnet_getHostByName (JNIEnv *env, const char *hostname, 
cpnet_address ***adresses, jint *addresses_count);
 JNIEXPORT jint cpnet_getHostByAddr (JNIEnv *env, cpnet_address *addr, char 
*hostname, jint hostname_len);
+JNIEXPORT jint cpnet_aton (JNIEnv *env, const char *hostname, cpnet_address 
**addr);
 JNIEXPORT void cpnet_freeAddresses(JNIEnv * env, cpnet_address **addr, jint 
addresses_count);
 
 static inline cpnet_address *cpnet_newIPV4Address(JNIEnv * env)
Index: native/jni/native-lib/cpnet.c
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/native-lib/cpnet.c,v
retrieving revision 1.3
diff -u -r1.3 cpnet.c
--- native/jni/native-lib/cpnet.c       31 Aug 2006 19:56:03 -0000      1.3
+++ native/jni/native-lib/cpnet.c       8 Sep 2006 08:23:31 -0000
@@ -49,6 +49,7 @@
 #include <sys/ioctl.h>
 #include <sys/time.h>
 #include <unistd.h>
+#include <arpa/inet.h>
 
 #include "cpnet.h"
 
@@ -709,6 +710,49 @@
   return 0;
 }
 
+jint cpnet_aton (JNIEnv *env, const char *hostname, cpnet_address **addr)
+{
+  jbyte *bytes = NULL;
+#ifdef HAVE_INET_PTON
+  jbyte inet6_addr[16];
+#endif
+
+#ifdef HAVE_INET_ATON
+  struct in_addr laddr;
+  if (inet_aton (hostname, &laddr))
+    {
+      bytes = (jbyte *) &laddr;
+    }
+#elif defined(HAVE_INET_ADDR)
+#if ! HAVE_IN_ADDR_T
+  typedef jint in_addr_t;
+#endif
+  in_addr_t laddr = inet_addr (hostname);
+  if (laddr != (in_addr_t)(-1))
+    {
+      bytes = (jbyte *) &laddr;
+    }
+#endif
+  if (bytes)
+    {
+      *addr = cpnet_newIPV4Address(env);
+      cpnet_bytesToIPV4Address(*addr, bytes);
+      return 0;
+    }
+
+#ifdef HAVE_INET_PTON
+  if (inet_pton (AF_INET6, hostname, inet6_addr) > 0)
+    {
+      *addr = cpnet_newIPV6Address(env);
+      cpnet_bytesToIPV6Address(*addr, inet6_addr);
+      return 0;
+    }
+#endif
+
+  *addr = NULL;
+  return 0;
+}
+
 void cpnet_freeAddresses(JNIEnv * env, cpnet_address **addr, jint 
addresses_count)
 {
   jint i;
Index: configure.ac
===================================================================
RCS file: /cvsroot/classpath/classpath/configure.ac,v
retrieving revision 1.181
diff -u -r1.181 configure.ac
--- configure.ac        31 Aug 2006 19:56:03 -0000      1.181
+++ configure.ac        8 Sep 2006 08:23:34 -0000
@@ -373,6 +373,7 @@
                   fcntl \
                  mmap munmap mincore msync madvise getpagesize sysconf \
                  lstat readlink \
+                 inet_aton inet_addr inet_pton \
                  ])
 
   LIBMAGIC=
Index: java/net/Inet4Address.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/net/Inet4Address.java,v
retrieving revision 1.18
diff -u -r1.18 Inet4Address.java
--- java/net/Inet4Address.java  2 Oct 2005 22:58:42 -0000       1.18
+++ java/net/Inet4Address.java  8 Sep 2006 08:23:37 -0000
@@ -57,7 +57,7 @@
   static final long serialVersionUID = 3286316764910316507L;
 
   /**
-   * needed for serialization
+   * Inet4Address objects are serialized as InetAddress objects.
    */
   private Object writeReplace() throws ObjectStreamException
   {
Index: NEWS
===================================================================
RCS file: /cvsroot/classpath/classpath/NEWS,v
retrieving revision 1.166
diff -u -r1.166 NEWS
--- NEWS        5 Sep 2006 21:19:20 -0000       1.166
+++ NEWS        8 Sep 2006 08:23:40 -0000
@@ -16,6 +16,7 @@
 * Added firstNonNullClassLoader method to
   vm/reference/gnu/classpath/VMStackWalker.java. VMs are encouraged to
   provide a more efficient implementation.
+* Added aton method to vm/reference/java/net/VMInetAddress.java.
 
 New in release 0.92 (Aug 9, 2006)
 

Reply via email to