OSDN Git Service

Manual merge of change I3665f82b into master.
authorLorenzo Colitti <lorenzo@google.com>
Fri, 18 Sep 2009 22:25:06 +0000 (15:25 -0700)
committerLorenzo Colitti <lorenzo@google.com>
Tue, 29 Sep 2009 22:29:36 +0000 (15:29 -0700)
libcore/luni/src/main/java/java/net/InetAddress.java
libcore/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
libcore/luni/src/main/java/org/apache/harmony/luni/util/Inet6Util.java
libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet4AddressTest.java
libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet6AddressTest.java
libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java

index 0fa4796..33c25f3 100644 (file)
@@ -272,7 +272,7 @@ public class InetAddress extends Object implements Serializable {
             }
         }
 
-        byte[] hBytes = Inet6Util.createByteArrayFromIPAddressString(host);
+        byte[] hBytes = NETIMPL.ipStringToByteArray(host);
         if (hBytes.length == 4) {
             return (new InetAddress[] { new Inet4Address(hBytes) });
         } else if (hBytes.length == 16) {
@@ -301,7 +301,8 @@ public class InetAddress extends Object implements Serializable {
         return getAllByNameImpl(host, false)[0];
     }
 
-    /*
+    // BEGIN android-added
+    /**
      * Convenience method to convert a byte array to a string, converting
      * exceptions to runtime exceptions. This is used when passing in byte
      * arrays that have been verified to be correct and is necessary because
@@ -310,6 +311,8 @@ public class InetAddress extends Object implements Serializable {
      * UnknownHostException. Exceptions should never occur when the address is
      * valid, but they cannot be simply ignored because they could be due to
      * runtime errors such as out-of-memory conditions.
+     *
+     * @param ipaddress the byte array to convert
      */
     private static String ipAddressToString(byte[] ipaddress) {
         try {
@@ -318,6 +321,7 @@ public class InetAddress extends Object implements Serializable {
             throw new RuntimeException(e);
         }
     }
+    // END android-added
 
     /**
      * Gets the textual representation of this IP address.
@@ -735,8 +739,12 @@ public class InetAddress extends Object implements Serializable {
      * Returns true if the string is a host name, false if it is an IP Address.
      */
     private static boolean isHostName(String value) {
-        return !(Inet6Util.isValidIPV4Address(value) || Inet6Util
-                .isValidIP6Address(value));
+        try {
+            NETIMPL.ipStringToByteArray(value);
+            return false;
+        } catch (UnknownHostException e) {
+            return true;
+        }
     }
 
     /**
@@ -1278,173 +1286,6 @@ public class InetAddress extends Object implements Serializable {
         return value;
     }
 
-    /**
-     * Creates an InetAddress based on the {@code ipAddressString}. No error
-     * handling is performed here.
-     */
-    static InetAddress createHostNameFromIPAddress(String ipAddressString)
-            throws UnknownHostException {
-
-        InetAddress address = null;
-
-        if (Inet6Util.isValidIPV4Address(ipAddressString)) {
-            byte[] byteAddress = new byte[4];
-            String[] parts = ipAddressString.split("\\."); //$NON-NLS-1$
-            int length = parts.length;
-            if (length == 1) {
-                long value = Long.parseLong(parts[0]);
-                for (int i = 0; i < 4; i++) {
-                    byteAddress[i] = (byte) (value >> ((3 - i) * 8));
-                }
-            } else {
-                for (int i = 0; i < length; i++) {
-                    byteAddress[i] = (byte) Integer.parseInt(parts[i]);
-                }
-            }
-
-            // adjust for 2/3 parts address
-            if (length == 2) {
-                byteAddress[3] = byteAddress[1];
-                byteAddress[1] = 0;
-            }
-            if (length == 3) {
-                byteAddress[3] = byteAddress[2];
-                byteAddress[2] = 0;
-            }
-
-            address = new Inet4Address(byteAddress);
-        } else { // otherwise it must be ipv6
-
-            if (ipAddressString.charAt(0) == '[') {
-                ipAddressString = ipAddressString.substring(1, ipAddressString
-                        .length() - 1);
-            }
-
-            StringTokenizer tokenizer = new StringTokenizer(ipAddressString,
-                    ":.%", true); //$NON-NLS-1$
-            ArrayList<String> hexStrings = new ArrayList<String>();
-            ArrayList<String> decStrings = new ArrayList<String>();
-            String scopeString = null;
-            String token = ""; //$NON-NLS-1$
-            String prevToken = ""; //$NON-NLS-1$
-            String prevPrevToken = ""; //$NON-NLS-1$
-            int doubleColonIndex = -1; // If a double colon exists, we need to
-            // insert 0s.
-
-            // Go through the tokens, including the separators ':' and '.'
-            // When we hit a : or . the previous token will be added to either
-            // the hex list or decimal list. In the case where we hit a ::
-            // we will save the index of the hexStrings so we can add zeros
-            // in to fill out the string
-            while (tokenizer.hasMoreTokens()) {
-                prevPrevToken = prevToken;
-                prevToken = token;
-                token = tokenizer.nextToken();
-
-                if (token.equals(":")) { //$NON-NLS-1$
-                    if (prevToken.equals(":")) { //$NON-NLS-1$
-                        doubleColonIndex = hexStrings.size();
-                    } else if (!prevToken.equals("")) { //$NON-NLS-1$
-                        hexStrings.add(prevToken);
-                    }
-                } else if (token.equals(".")) { //$NON-NLS-1$
-                    decStrings.add(prevToken);
-                } else if (token.equals("%")) { //$NON-NLS-1$
-                    // add the last word before the % properly
-                    if (!prevToken.equals(":") && !prevToken.equals(".")) { //$NON-NLS-1$ //$NON-NLS-2$
-                        if (prevPrevToken.equals(":")) { //$NON-NLS-1$
-                            hexStrings.add(prevToken);
-                        } else if (prevPrevToken.equals(".")) { //$NON-NLS-1$
-                            decStrings.add(prevToken);
-                        }
-                    }
-
-                    // the rest should be the scope string
-                    scopeString = tokenizer.nextToken();
-                    while (tokenizer.hasMoreTokens()) {
-                        scopeString = scopeString + tokenizer.nextToken();
-                    }
-                }
-            }
-
-            if (prevToken.equals(":")) { //$NON-NLS-1$
-                if (token.equals(":")) { //$NON-NLS-1$
-                    doubleColonIndex = hexStrings.size();
-                } else {
-                    hexStrings.add(token);
-                }
-            } else if (prevToken.equals(".")) { //$NON-NLS-1$
-                decStrings.add(token);
-            }
-
-            // figure out how many hexStrings we should have
-            // also check if it is a IPv4 address
-            int hexStringsLength = 8;
-
-            // If we have an IPv4 address tagged on at the end, subtract
-            // 4 bytes, or 2 hex words from the total
-            if (decStrings.size() > 0) {
-                hexStringsLength -= 2;
-            }
-
-            // if we hit a double Colon add the appropriate hex strings
-            if (doubleColonIndex != -1) {
-                int numberToInsert = hexStringsLength - hexStrings.size();
-                for (int i = 0; i < numberToInsert; i++) {
-                    hexStrings.add(doubleColonIndex, "0"); //$NON-NLS-1$
-                }
-            }
-
-            byte ipByteArray[] = new byte[16];
-
-            // Finally convert these strings to bytes...
-            for (int i = 0; i < hexStrings.size(); i++) {
-                Inet6Util.convertToBytes(hexStrings.get(i), ipByteArray, i * 2);
-            }
-
-            // Now if there are any decimal values, we know where they go...
-            for (int i = 0; i < decStrings.size(); i++) {
-                ipByteArray[i + 12] = (byte) (Integer.parseInt(decStrings
-                        .get(i)) & 255);
-            }
-
-            // now check to see if this guy is actually and IPv4 address
-            // an ipV4 address is ::FFFF:d.d.d.d
-            boolean ipV4 = true;
-            for (int i = 0; i < 10; i++) {
-                if (ipByteArray[i] != 0) {
-                    ipV4 = false;
-                    break;
-                }
-            }
-
-            if (ipByteArray[10] != -1 || ipByteArray[11] != -1) {
-                ipV4 = false;
-            }
-
-            if (ipV4) {
-                byte ipv4ByteArray[] = new byte[4];
-                for (int i = 0; i < 4; i++) {
-                    ipv4ByteArray[i] = ipByteArray[i + 12];
-                }
-                address = InetAddress.getByAddress(ipv4ByteArray);
-            } else {
-                int scopeId = 0;
-                if (scopeString != null) {
-                    try {
-                        scopeId = Integer.parseInt(scopeString);
-                    } catch (Exception e) {
-                        // this should not occur as we should not get into this
-                        // function unless the address is in a valid format
-                    }
-                }
-                address = InetAddress.getByAddress(ipByteArray, scopeId);
-            }
-        }
-
-        return address;
-    }
-
     static boolean preferIPv6Addresses() {
         String result = AccessController.doPrivileged(new PriviAction<String>(
                 "java.net.preferIPv6Addresses")); //$NON-NLS-1$
index 1345341..fb47f0d 100644 (file)
@@ -218,9 +218,14 @@ public interface INetworkSystem {
 
     public void setInetAddress(InetAddress sender, byte[] address);
 
+    // BEGIN android-added
     public String byteArrayToIpString(byte[] address)
             throws UnknownHostException;
 
+    public byte[] ipStringToByteArray(String address)
+            throws UnknownHostException;
+    // END android-added
+
     // BEGIN android-removed
     // public boolean isReachableByICMP(InetAddress dest,InetAddress source,int ttl,int timeout);
     // END android-removed
index 0fa25ea..bd6a609 100644 (file)
@@ -242,6 +242,9 @@ final class OSNetworkSystem implements INetworkSystem {
     public native String byteArrayToIpString(byte[] address)
             throws UnknownHostException;
 
+    public native byte[] ipStringToByteArray(String address)
+            throws UnknownHostException;
+
     static native int getSocketFlagsImpl();
 
     public InetAddress getSocketLocalAddress(FileDescriptor fd,
index 4dae1c3..55914de 100644 (file)
@@ -24,244 +24,6 @@ import java.util.StringTokenizer;
  */
 public class Inet6Util {
 
-       /**
-        * Creates an byte[] based on an ipAddressString. No error handling is
-        * performed here.
-        */
-       public static byte[] createByteArrayFromIPAddressString(
-                       String ipAddressString) {
-
-               if (isValidIPV4Address(ipAddressString)) {
-            StringTokenizer tokenizer = new StringTokenizer(ipAddressString, ".");
-                       String token = "";
-                       int tempInt = 0;
-                       byte[] byteAddress = new byte[4];
-                       for (int i = 0; i < 4; i++) {
-                               token = tokenizer.nextToken();
-                               tempInt = Integer.parseInt(token);
-                               byteAddress[i] = (byte) tempInt;
-                       }
-
-                       return byteAddress;
-               }
-
-               if (ipAddressString.charAt(0) == '[') {
-            ipAddressString = ipAddressString.substring(1, ipAddressString.length() - 1);
-        }
-
-        StringTokenizer tokenizer = new StringTokenizer(ipAddressString, ":.", true);
-        ArrayList<String> hexStrings = new ArrayList<String>();
-        ArrayList<String> decStrings = new ArrayList<String>();
-        String token = "";
-        String prevToken = "";
-        // If a double colon exists, we need to insert 0s.
-        int doubleColonIndex = -1;
-
-        /*
-         * Go through the tokens, including the separators ':' and '.' When we
-         * hit a : or . the previous token will be added to either the hex list
-         * or decimal list. In the case where we hit a :: we will save the index
-         * of the hexStrings so we can add zeros in to fill out the string
-         */
-               while (tokenizer.hasMoreTokens()) {
-                       prevToken = token;
-                       token = tokenizer.nextToken();
-
-                       if (token.equals(":")) {
-                               if (prevToken.equals(":")) {
-                                       doubleColonIndex = hexStrings.size();
-                               } else if (!prevToken.equals("")) {
-                                       hexStrings.add(prevToken);
-                               }
-                       } else if (token.equals(".")) {
-                               decStrings.add(prevToken);
-                       }
-               }
-
-               if (prevToken.equals(":")) {
-                       if (token.equals(":")) {
-                               doubleColonIndex = hexStrings.size();
-                       } else {
-                               hexStrings.add(token);
-                       }
-               } else if (prevToken.equals(".")) {
-                       decStrings.add(token);
-               }
-
-               // figure out how many hexStrings we should have
-               // also check if it is a IPv4 address
-               int hexStringsLength = 8;
-
-               // If we have an IPv4 address tagged on at the end, subtract
-               // 4 bytes, or 2 hex words from the total
-               if (decStrings.size() > 0) {
-                       hexStringsLength -= 2;
-               }
-
-               // if we hit a double Colon add the appropriate hex strings
-               if (doubleColonIndex != -1) {
-                       int numberToInsert = hexStringsLength - hexStrings.size();
-                       for (int i = 0; i < numberToInsert; i++) {
-                               hexStrings.add(doubleColonIndex, "0");
-                       }
-               }
-
-               byte ipByteArray[] = new byte[16];
-
-               // Finally convert these strings to bytes...
-               for (int i = 0; i < hexStrings.size(); i++) {
-                       convertToBytes(hexStrings.get(i), ipByteArray, i * 2);
-               }
-
-               // Now if there are any decimal values, we know where they go...
-               for (int i = 0; i < decStrings.size(); i++) {
-            ipByteArray[i + 12] = (byte) (Integer.parseInt(decStrings.get(i)) & 255);
-        }
-
-               // now check to see if this guy is actually and IPv4 address
-               // an ipV4 address is ::FFFF:d.d.d.d
-               boolean ipV4 = true;
-               for (int i = 0; i < 10; i++) {
-                       if (ipByteArray[i] != 0) {
-                               ipV4 = false;
-                               break;
-                       }
-               }
-
-               if (ipByteArray[10] != -1 || ipByteArray[11] != -1) {
-                       ipV4 = false;
-               }
-
-               if (ipV4) {
-                       byte ipv4ByteArray[] = new byte[4];
-                       for (int i = 0; i < 4; i++) {
-                               ipv4ByteArray[i] = ipByteArray[i + 12];
-                       }
-                       return ipv4ByteArray;
-               }
-
-               return ipByteArray;
-
-       }
-
-       /** Converts a 4 character hex word into a 2 byte word equivalent */
-       public static void convertToBytes(String hexWord, byte ipByteArray[],
-                       int byteIndex) {
-
-               int hexWordLength = hexWord.length();
-               int hexWordIndex = 0;
-               ipByteArray[byteIndex] = 0;
-               ipByteArray[byteIndex + 1] = 0;
-               int charValue;
-
-               // high order 4 bits of first byte
-               if (hexWordLength > 3) {
-                       charValue = getIntValue(hexWord.charAt(hexWordIndex++));
-                       ipByteArray[byteIndex] = (byte) (ipByteArray[byteIndex] | (charValue << 4));
-               }
-
-               // low order 4 bits of the first byte
-               if (hexWordLength > 2) {
-                       charValue = getIntValue(hexWord.charAt(hexWordIndex++));
-                       ipByteArray[byteIndex] = (byte) (ipByteArray[byteIndex] | charValue);
-               }
-
-               // high order 4 bits of second byte
-               if (hexWordLength > 1) {
-                       charValue = getIntValue(hexWord.charAt(hexWordIndex++));
-                       ipByteArray[byteIndex + 1] = (byte) (ipByteArray[byteIndex + 1] | (charValue << 4));
-               }
-
-               // low order 4 bits of the first byte
-               charValue = getIntValue(hexWord.charAt(hexWordIndex));
-               ipByteArray[byteIndex + 1] = (byte) (ipByteArray[byteIndex + 1] | charValue & 15);
-       }
-
-       static int getIntValue(char c) {
-
-               switch (c) {
-               case '0':
-                       return 0;
-               case '1':
-                       return 1;
-               case '2':
-                       return 2;
-               case '3':
-                       return 3;
-               case '4':
-                       return 4;
-               case '5':
-                       return 5;
-               case '6':
-                       return 6;
-               case '7':
-                       return 7;
-               case '8':
-                       return 8;
-               case '9':
-                       return 9;
-               }
-
-               c = Character.toLowerCase(c);
-               switch (c) {
-               case 'a':
-                       return 10;
-               case 'b':
-                       return 11;
-               case 'c':
-                       return 12;
-               case 'd':
-                       return 13;
-               case 'e':
-                       return 14;
-               case 'f':
-                       return 15;
-               }
-               return 0;
-       }
-
-       private static boolean isIPv4MappedAddress(byte ipAddress[]) {
-
-               // Check if the address matches ::FFFF:d.d.d.d
-               // The first 10 bytes are 0. The next to are -1 (FF).
-               // The last 4 bytes are varied.
-               for (int i = 0; i < 10; i++) {
-                       if (ipAddress[i] != 0) {
-                               return false;
-                       }
-               }
-
-               if (ipAddress[10] != -1 || ipAddress[11] != -1) {
-                       return false;
-               }
-
-               return true;
-
-       }
-
-       /**
-        * Takes the byte array and creates an integer out of four bytes starting at
-        * start as the high-order byte. This method makes no checks on the validity
-        * of the parameters.
-        */
-       public static int bytesToInt(byte bytes[], int start) {
-               // First mask the byte with 255, as when a negative
-               // signed byte converts to an integer, it has bits
-               // on in the first 3 bytes, we are only concerned
-               // about the right-most 8 bits.
-               // Then shift the rightmost byte to align with its
-               // position in the integer.
-               int value = ((bytes[start + 3] & 255))
-                               | ((bytes[start + 2] & 255) << 8)
-                               | ((bytes[start + 1] & 255) << 16)
-                               | ((bytes[start] & 255) << 24);
-               return value;
-       }
-
-       public static String addressToString(int value) {
-               return ((value >> 24) & 0xff) + "." + ((value >> 16) & 0xff) + "."
-                               + ((value >> 8) & 0xff) + "." + (value & 0xff);
-       }
 
     public static boolean isIP6AddressInFullForm(String ipAddress) {
         if (isValidIP6Address(ipAddress)) {
index 6d258e0..dd96498 100644 (file)
  * limitations under the License.
  */
 
+// BEGIN android-changed
+//
+// This file has been substantially reworked in order to provide more IPv6
+// support and to move functionality from Java to native code where it made
+// sense (e.g. when converting between IP addresses, socket structures, and
+// strings, for which there exist fast and robust native implementations).
+
 #define LOG_TAG "OSNetworkSystem"
 
 #include "JNIHelp.h"
@@ -26,6 +33,7 @@
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <netdb.h>
+#include <arpa/inet.h>
 #include <sys/time.h>
 #include <stdlib.h>
 #include <sys/ioctl.h>
@@ -215,28 +223,6 @@ static void throwNullPointerException(JNIEnv *env) {
 }
 
 /**
- * Converts a 4-byte array to a native address structure. Throws a
- * NullPointerException or an IOException in case of error. This is
- * signaled by a return value of -1. The normal return value is 0.
- */
-static int javaAddressToStructIn(
-        JNIEnv *env, jbyteArray java_address, struct in_addr *address) {
-    if (java_address == NULL) {
-        return -1;
-    }
-
-    if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
-        return -1;
-    }
-
-    memset(address, 0, sizeof(address));
-
-    jbyte* dst = reinterpret_cast<jbyte*>(&(address->s_addr));
-    env->GetByteArrayRegion(java_address, 0, sizeof(address->s_addr), dst);
-    return 0;
-}
-
-/**
  * Converts a native address structure to a Java byte array. Throws a
  * NullPointerException or an IOException in case of error. This is
  * signaled by a return value of -1. The normal return value is 0.
@@ -246,7 +232,7 @@ static int javaAddressToStructIn(
  * @exception SocketException the address family is unknown, or out of memory
  *
  */
-static jbyteArray socketAddressToAddressBytes(JNIEnv *env,
+static jbyteArray socketAddressToByteArray(JNIEnv *env,
         struct sockaddr_storage *address) {
 
     void *rawAddress;
@@ -293,6 +279,34 @@ static int getSocketAddressPort(struct sockaddr_storage *address) {
 }
 
 /**
+ * Checks whether a socket address structure contains an IPv4-mapped address.
+ *
+ * @param address the socket address structure to check
+ * @return true if address contains an IPv4-mapped address, false otherwise.
+ */
+static bool isMappedAddress(sockaddr *address) {
+    if (! address || address->sa_family != AF_INET6) {
+        return false;
+    }
+    in6_addr addr = ((sockaddr_in6 *) address)->sin6_addr;
+    return (addr.s6_addr32[0] == 0 &&
+            addr.s6_addr32[1] == 0 &&
+            addr.s6_addr32[2] == htonl(0xffff));
+}
+
+/**
+ * Checks whether a 16-byte array represents an IPv4-mapped IPv6 address.
+ *
+ * @param addressBytes the address to check. Must be 16 bytes long.
+ * @return true if address contains an IPv4-mapped address, false otherwise.
+ */
+static bool isJavaMappedAddress(jbyte *addressBytes) {
+    static const unsigned char mappedBytes[] = {
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
+    return !memcmp(mappedBytes, addressBytes, sizeof(mappedBytes));
+}
+
+/**
  * Converts a native address structure to an InetAddress object.
  * Throws a NullPointerException or an IOException in case of
  * error.
@@ -304,7 +318,7 @@ static int getSocketAddressPort(struct sockaddr_storage *address) {
 static jobject socketAddressToInetAddress(JNIEnv *env,
         struct sockaddr_storage *sockaddress) {
 
-    jbyteArray byteArray = socketAddressToAddressBytes(env, sockaddress);
+    jbyteArray byteArray = socketAddressToByteArray(env, sockaddress);
     if (byteArray == NULL)  // Exception has already been thrown.
         return NULL;
 
@@ -313,6 +327,39 @@ static jobject socketAddressToInetAddress(JNIEnv *env,
 }
 
 /**
+ * Converts an IPv4-mapped IPv6 address to an IPv4 address. Performs no error
+ * checking.
+ *
+ * @param address the address to convert. Must contain an IPv4-mapped address.
+ * @param outputAddress the converted address. Will contain an IPv4 address.
+ */
+static void convertMappedToIpv4(sockaddr_in6 *sin6, sockaddr_in *sin) {
+  memset(sin, 0, sizeof(*sin));
+  sin->sin_family = AF_INET;
+  sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
+  sin->sin_port = sin6->sin6_port;
+}
+
+/**
+ * Converts an IPv4 address to an IPv4-mapped IPv6 address. Performs no error
+ * checking.
+ *
+ * @param address the address to convert. Must contain an IPv4 address.
+ * @param outputAddress the converted address. Will contain an IPv6 address.
+ * @param mapUnspecified if true, convert 0.0.0.0 to ::ffff:0:0; if false, to ::
+ */
+static void convertIpv4ToMapped(struct sockaddr_in *sin,
+        struct sockaddr_in6 *sin6, bool mapUnspecified) {
+  memset(sin6, 0, sizeof(*sin6));
+  sin6->sin6_family = AF_INET6;
+  sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
+  if (sin->sin_addr.s_addr != 0  || mapUnspecified) {
+      sin6->sin6_addr.s6_addr32[2] = htonl(0xffff);
+  }
+  sin6->sin6_port = sin->sin_port;
+}
+
+/**
  * Converts an InetAddress object and port number to a native address structure.
  * Throws a NullPointerException or a SocketException in case of
  * error. This is signaled by a return value of -1. The normal
@@ -332,8 +379,9 @@ static int byteArrayToSocketAddress(JNIEnv *env,
         throwNullPointerException(env);
         return EFAULT;
     }
-    // Convert the IP address bytes to the proper IP address type.
     size_t addressLength = env->GetArrayLength(addressBytes);
+
+    // Convert the IP address bytes to the proper IP address type.
     if (addressLength == 4) {
         // IPv4 address.
         sockaddr_in *sin = reinterpret_cast<sockaddr_in*>(sockaddress);
@@ -473,6 +521,84 @@ static jstring osNetworkSystem_byteArrayToIpString(JNIEnv *env, jclass clazz,
 }
 
 /**
+ * Convert a Java string representing an IP address to a Java byte array.
+ * The formats accepted are:
+ * - IPv4:
+ *   - 1.2.3.4
+ *   - 1.2.4
+ *   - 1.4
+ *   - 4
+ * - IPv6
+ *   - Compressed form (2001:db8::1)
+ *   - Uncompressed form (2001:db8:0:0:0:0:0:1)
+ *   - IPv4-compatible (::192.0.2.0)
+ *   - With an embedded IPv4 address (2001:db8::192.0.2.0).
+ * IPv6 addresses may appear in square brackets.
+ *
+ * @param addressByteArray the byte array to convert.
+ *
+ * @return a string with the textual representation of the address.
+ *
+ * @throws UnknownHostException the IP address was invalid.
+ */
+static jbyteArray osNetworkSystem_ipStringToByteArray(JNIEnv *env, jclass clazz,
+        jstring javaString) {
+    if (javaString == NULL) {
+        throwNullPointerException(env);
+    }
+
+    char ipString[INET6_ADDRSTRLEN];
+    int stringLength = env->GetStringUTFLength(javaString);
+    env->GetStringUTFRegion(javaString, 0, stringLength, ipString);
+
+    // Accept IPv6 addresses (only) in square brackets for compatibility.
+    if (ipString[0] == '[' && ipString[stringLength - 1] == ']' &&
+            index(ipString, ':') != NULL) {
+        memmove(ipString, ipString + 1, stringLength - 2);
+        ipString[stringLength - 2] = '\0';
+    }
+
+    jbyteArray result = NULL;
+    sockaddr_in sin;
+    addrinfo hints, *res;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_NUMERICHOST;
+    int ret = getaddrinfo(ipString, NULL, &hints, &res);
+    if (ret == 0 && res) {
+        // Convert mapped addresses to IPv4 addresses if necessary.
+        if (res->ai_family == AF_INET6 && isMappedAddress(res->ai_addr)) {
+            convertMappedToIpv4((sockaddr_in6 *) res->ai_addr, &sin);
+            result = socketAddressToByteArray(env, (sockaddr_storage *) &sin);
+        } else {
+            result = socketAddressToByteArray(env,
+                    (sockaddr_storage *) res->ai_addr);
+        }
+    } else {
+        // For backwards compatibility, deal with address formats that
+        // getaddrinfo does not support. For example, 1.2.3, 1.3, and even 3 are
+        // valid IPv4 addresses according to the Java API. If getaddrinfo fails,
+        // try to use inet_aton.
+        if (inet_aton(ipString, &sin.sin_addr)) {
+            sin.sin_port = 0;
+            sin.sin_family = AF_INET;
+            result = socketAddressToByteArray(env, (sockaddr_storage *) &sin);
+        }
+    }
+
+    if (res) {
+        freeaddrinfo(res);
+    }
+
+    if (! result) {
+        env->ExceptionClear();
+        jniThrowException(env, "java/net/UnknownHostException",
+                gai_strerror(ret));
+    }
+
+    return result;
+}
+
+/**
  * Answer a new java.lang.Boolean object.
  *
  * @param env   pointer to the JNI library
@@ -924,41 +1050,50 @@ static int getSocketAddressFamily(int socket) {
 }
 
 /**
- * Converts an IPv4-mapped IPv6 address to an IPv4 address. Performs no error
- * checking.
+ * A helper method, to set the connect context to a Long object.
  *
- * @param address the address to convert. Must contain an IPv4-mapped address.
- * @param outputAddress the converted address. Will contain an IPv4 address.
+ * @param env  pointer to the JNI library
+ * @param longclass Java Long Object
  */
-static void convertMappedToIpv4(sockaddr_storage *address,
-        sockaddr_storage *outputAddress) {
-  memset(outputAddress, 0, sizeof(sockaddr_in));
-  const sockaddr_in6 *sin6 = ((sockaddr_in6 *) address);
-  sockaddr_in *sin = ((sockaddr_in *) outputAddress);
-  sin->sin_family = AF_INET;
-  sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
-  sin->sin_port = sin6->sin6_port;
-}
+void setConnectContext(JNIEnv *env,jobject longclass,jbyte * context) {
+    jclass descriptorCLS;
+    jfieldID descriptorFID;
+    descriptorCLS = env->FindClass("java/lang/Long");
+    descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
+    env->SetLongField(longclass, descriptorFID, (jlong)((jint)context));
+};
 
 /**
- * Converts an IPv4 address to an IPv4-mapped IPv6 address. Performs no error
- * checking.
+ * A helper method, to get the connect context.
  *
- * @param address the address to convert. Must contain an IPv4 address.
- * @param outputAddress the converted address. Will contain an IPv6 address.
- * @param mapUnspecified if true, convert 0.0.0.0 to ::ffff:0:0; if false, to ::
+ * @param env  pointer to the JNI library
+ * @param longclass Java Long Object
  */
-static void convertIpv4ToMapped(struct sockaddr_storage *address,
-        struct sockaddr_storage *outputAddress, bool mapUnspecified) {
-  memset(outputAddress, 0, sizeof(struct sockaddr_in6));
-  const struct sockaddr_in *sin = ((struct sockaddr_in *) address);
-  struct sockaddr_in6 *sin6 = ((struct sockaddr_in6 *) outputAddress);
-  sin6->sin6_family = AF_INET6;
-  sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
-  if (sin->sin_addr.s_addr != 0  || mapUnspecified) {
-      sin6->sin6_addr.s6_addr32[2] = htonl(0xffff);
-  }
-  sin6->sin6_port = sin->sin_port;
+jbyte *getConnectContext(JNIEnv *env, jobject longclass) {
+    jclass descriptorCLS;
+    jfieldID descriptorFID;
+    descriptorCLS = env->FindClass("java/lang/Long");
+    descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
+    return (jbyte*) ((jint)env->GetLongField(longclass, descriptorFID));
+};
+
+// typical ip checksum
+unsigned short ip_checksum(unsigned short* buffer, int size) {
+    register unsigned short * buf = buffer;
+    register int bufleft = size;
+    register unsigned long sum = 0;
+
+    while (bufleft > 1) {
+        sum = sum + (*buf++);
+        bufleft = bufleft - sizeof(unsigned short );
+    }
+    if (bufleft) {
+        sum = sum + (*(unsigned char*)buf);
+    }
+    sum = (sum >> 16) + (sum & 0xffff);
+    sum += (sum >> 16);
+
+    return (unsigned short )(~sum);
 }
 
 /**
@@ -969,11 +1104,12 @@ static void convertIpv4ToMapped(struct sockaddr_storage *address,
  * @param socketAddress the address to connect to
  */
 static int doConnect(int socket, struct sockaddr_storage *socketAddress) {
-    struct sockaddr_storage mappedAddress;
-    struct sockaddr_storage *realAddress;
+    sockaddr_storage mappedAddress;
+    sockaddr_storage *realAddress;
     if (socketAddress->ss_family == AF_INET &&
         getSocketAddressFamily(socket) == AF_INET6) {
-        convertIpv4ToMapped(socketAddress, &mappedAddress, true);
+        convertIpv4ToMapped((sockaddr_in *) socketAddress,
+                (sockaddr_in6 *) &mappedAddress, true);
         realAddress = &mappedAddress;
     } else {
         realAddress = socketAddress;
@@ -998,7 +1134,8 @@ static int doBind(int socket, struct sockaddr_storage *socketAddress) {
     struct sockaddr_storage *realAddress;
     if (socketAddress->ss_family == AF_INET &&
         getSocketAddressFamily(socket) == AF_INET6) {
-        convertIpv4ToMapped(socketAddress, &mappedAddress, false);
+        convertIpv4ToMapped((sockaddr_in *) socketAddress,
+                (sockaddr_in6 *) &mappedAddress, false);
         realAddress = &mappedAddress;
     } else {
         realAddress = socketAddress;
@@ -1256,7 +1393,6 @@ static int interfaceIndexFromMulticastSocket(int socket) {
         return -1;
 }
 
-
 /**
  * Join/Leave the nominated multicast group on the specified socket.
  * Implemented by setting the multicast 'add membership'/'drop membership'
@@ -1514,7 +1650,6 @@ static int createSocketFileDescriptor(JNIEnv* env, jobject fileDescriptor,
     return sock;
 }
 
-
 static void osNetworkSystem_createStreamSocketImpl(JNIEnv* env, jclass clazz,
         jobject fileDescriptor, jboolean preferIPv4Stack) {
     // LOGD("ENTER createSocketImpl");
@@ -2272,7 +2407,7 @@ static jint osNetworkSystem_receiveDatagramDirectImpl(JNIEnv* env, jclass clazz,
     }
 
     if (packet != NULL) {
-        jbyteArray addr = socketAddressToAddressBytes(env, &sockAddr);
+        jbyteArray addr = socketAddressToByteArray(env, &sockAddr);
         if (addr == NULL)  // Exception has already been thrown.
             return 0;
         int port = getSocketAddressPort(&sockAddr);
@@ -3589,6 +3724,7 @@ static JNINativeMethod gMethods[] = {
     { "setInetAddressImpl",                "(Ljava/net/InetAddress;[B)V",                                              (void*) osNetworkSystem_setInetAddressImpl                 },
     { "inheritedChannelImpl",              "()Ljava/nio/channels/Channel;",                                            (void*) osNetworkSystem_inheritedChannelImpl               },
     { "byteArrayToIpString",               "([B)Ljava/lang/String;",                                                   (void*) osNetworkSystem_byteArrayToIpString                },
+    { "ipStringToByteArray",               "(Ljava/lang/String;)[B",                                                   (void*) osNetworkSystem_ipStringToByteArray                },
 };
 
 int register_org_apache_harmony_luni_platform_OSNetworkSystem(JNIEnv* env) {
@@ -3597,3 +3733,4 @@ int register_org_apache_harmony_luni_platform_OSNetworkSystem(JNIEnv* env) {
             gMethods,
             NELEM(gMethods));
 }
+// END android-changed
index 920f137..163db31 100644 (file)
@@ -17,7 +17,6 @@
 
 package org.apache.harmony.luni.tests.java.net;
 
-import dalvik.annotation.KnownFailure;
 import dalvik.annotation.TestTargetClass; 
 import dalvik.annotation.TestTargets;
 import dalvik.annotation.TestLevel;
@@ -484,12 +483,6 @@ public class Inet4AddressTest extends junit.framework.TestCase {
         method = "equals",
         args = {java.lang.Object.class}
     )
-    @KnownFailure("127.0.0 is not recognized as a valid IP address. " +
-            "Unfortunately, despite the fact that these IP address formats " +
-            "have been the cause of numerous phishing and security " +
-            "vulnerabilities in the past, and most other languages refuse " +
-            "them, the RI documentation explicitly specifies that they are " +
-            "supported. Fix the code to support these.")
     public void test_equals() throws Exception {
         InetAddress addr = Inet4Address.getByName("239.191.255.255");
         assertTrue(addr.equals(addr));
@@ -508,7 +501,6 @@ public class Inet4AddressTest extends junit.framework.TestCase {
         method = "getHostAddress",
         args = {}
     )
-    @KnownFailure("1, 1.1 and 1.1.1 are not recognized as valid IP addresses.")
     public void test_getHostAddress() throws Exception {
         InetAddress addr = Inet4Address.getByName("localhost");
         assertEquals("127.0.0.1", addr.getHostAddress());
@@ -535,7 +527,6 @@ public class Inet4AddressTest extends junit.framework.TestCase {
         method = "hashCode",
         args = {}
     )
-    @KnownFailure("1.1 and 1.1.1 are not recognized as valid IP addresses.")
     public void test_hashCode() throws Exception {
         InetAddress addr1 = Inet4Address.getByName("1.1");
         InetAddress addr2 = Inet4Address.getByName("1.1.1");
index 62952d9..98ae45e 100644 (file)
@@ -17,7 +17,6 @@
 
 package org.apache.harmony.luni.tests.java.net;
 
-import dalvik.annotation.KnownFailure;
 import dalvik.annotation.TestTargetClass; 
 import dalvik.annotation.TestLevel;
 import dalvik.annotation.TestTargetNew;
@@ -1153,12 +1152,6 @@ public class Inet6AddressTest extends junit.framework.TestCase {
         method = "equals",
         args = {java.lang.Object.class}
     )
-    @KnownFailure("127.0.0 is not recognized as a valid IP address. " +
-            "Unfortunately, despite the fact that these IP address formats " +
-            "have been the cause of numerous phishing and security " +
-            "vulnerabilities in the past, and most other languages refuse " +
-            "them, the RI documentation explicitly specifies that they are " +
-            "supported. Fix the code to support these.")
     public void test_equals() throws Exception {
         InetAddress addr = Inet6Address.getByName("239.191.255.255");
         assertTrue(addr.equals(addr));
@@ -1177,7 +1170,6 @@ public class Inet6AddressTest extends junit.framework.TestCase {
         method = "getHostAddress",
         args = {}
     )
-    @KnownFailure("1, 1.1 and 1.1.1 are not recognized as valid IP addresses.")
     public void test_getHostAddress() throws Exception {
         InetAddress aAddr = Inet6Address.getByName("localhost");
         assertEquals("127.0.0.1", aAddr.getHostAddress());
@@ -1201,7 +1193,9 @@ public class Inet6AddressTest extends junit.framework.TestCase {
                 0x25, (byte) 0xFF, (byte) 0xFE, (byte) 0xF8, (byte) 0x7C,
                 (byte) 0xB2 };
         aAddr = Inet6Address.getByAddress(bAddr);
-        assertEquals("fe80:0:0:0:211:25ff:fef8:7cb2", aAddr.getHostAddress());
+        String aString = aAddr.getHostAddress();
+        assertTrue(aString.equals("fe80:0:0:0:211:25ff:fef8:7cb2") ||
+                   aString.equals("fe80::211:25ff:fef8:7cb2"));
 
         byte[] cAddr = { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
                 (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
@@ -1215,7 +1209,9 @@ public class Inet6AddressTest extends junit.framework.TestCase {
                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
         aAddr = Inet6Address.getByAddress(dAddr);
-        assertEquals("0:0:0:0:0:0:0:0", aAddr.getHostAddress());
+        aString = aAddr.getHostAddress();
+        assertTrue(aString.equals("0:0:0:0:0:0:0:0") ||
+                   aString.equals("::"));
 
         byte[] eAddr = { (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03,
                 (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
@@ -1238,7 +1234,6 @@ public class Inet6AddressTest extends junit.framework.TestCase {
         method = "hashCode",
         args = {}
     )
-    @KnownFailure("1.1 and 1.1.1 are not recognized as valid IP addresses.")
     public void test_hashCode() throws Exception {
         InetAddress addr1 = Inet6Address.getByName("1.1");
         InetAddress addr2 = Inet6Address.getByName("1.1.1");
index 6087a46..5635ecb 100644 (file)
@@ -18,7 +18,6 @@
 package org.apache.harmony.luni.tests.java.net;
 
 import dalvik.annotation.BrokenTest;
-import dalvik.annotation.KnownFailure;
 import dalvik.annotation.TestTargetClass;
 import dalvik.annotation.TestTargets;
 import dalvik.annotation.TestLevel;
@@ -255,12 +254,6 @@ public class InetAddressTest extends junit.framework.TestCase {
         method = "getByName",
         args = {java.lang.String.class}
     )
-    @KnownFailure("1.2.3 and 1.2 are not recognized as valid IPv4 addresses. " +
-            "Unfortunately, despite the fact that these IP address formats " +
-            "have been the cause of numerous phishing and security " +
-            "vulnerabilities in the past, and most other languages refuse " +
-            "them, the RI documentation explicitly specifies that they are " +
-            "supported. Fix the code to support these.")
     public void test_getByNameLjava_lang_String() throws Exception {
         // Test for method java.net.InetAddress
         // java.net.InetAddress.getByName(java.lang.String)