Merge change 26285 into eclair

* changes:
  Use native code to convert strings to IP addresses.
diff --git a/libcore/luni/src/main/java/java/net/InetAddress.java b/libcore/luni/src/main/java/java/net/InetAddress.java
index 0fa4796..33c25f3 100644
--- a/libcore/luni/src/main/java/java/net/InetAddress.java
+++ b/libcore/luni/src/main/java/java/net/InetAddress.java
@@ -272,7 +272,7 @@
             }
         }
 
-        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 @@
         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 @@
      * 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 @@
             throw new RuntimeException(e);
         }
     }
+    // END android-added
 
     /**
      * Gets the textual representation of this IP address.
@@ -735,8 +739,12 @@
      * 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 @@
         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$
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
index 1345341..fb47f0d 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
@@ -218,9 +218,14 @@
 
     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
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
index 0fa25ea..bd6a609 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
@@ -242,6 +242,9 @@
     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,
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/util/Inet6Util.java b/libcore/luni/src/main/java/org/apache/harmony/luni/util/Inet6Util.java
index 4dae1c3..55914de 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/util/Inet6Util.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/util/Inet6Util.java
@@ -24,244 +24,6 @@
  */
 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)) {
diff --git a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index 909f211..ac2b4e2 100644
--- a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -14,6 +14,13 @@
  * 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>
@@ -217,36 +225,6 @@
 }
 
 /**
- * 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) {
-
-    memset(address, 0, sizeof(address));
-
-    if (java_address == NULL) {
-        return -1;
-    }
-
-    if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
-        return -1;
-    }
-
-    jbyte * java_address_bytes
-        =  env->GetByteArrayElements(java_address, NULL);
-
-    memcpy(&(address->s_addr),
-        java_address_bytes,
-        sizeof(address->s_addr));
-
-    env->ReleaseByteArrayElements(java_address, java_address_bytes, JNI_ABORT);
-
-    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.
@@ -256,7 +234,7 @@
  * @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;
@@ -303,6 +281,34 @@
 }
 
 /**
+ * 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. This is signaled by a return value of -1. The normal
@@ -315,7 +321,7 @@
 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;
 
@@ -324,6 +330,39 @@
 }
 
 /**
+ * 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
@@ -343,8 +382,9 @@
       throwNullPointerException(env);
       return EFAULT;
     }
-    // Convert the IP address bytes to the proper IP address type.
     size_t addressLength = env->GetArrayLength(addressByteArray);
+
+    // Convert the IP address bytes to the proper IP address type.
     if (addressLength == 4) {
         // IPv4 address.
         sockaddr_in *sin = (sockaddr_in *) sockaddress;
@@ -481,6 +521,84 @@
 }
 
 /**
+ * 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
@@ -984,43 +1102,6 @@
     return (unsigned short )(~sum);
 }
 
-/**
- * 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_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;
-}
-
-/**
- * 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_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;
-}
 
 /**
  * Wrapper for connect() that converts IPv4 addresses to IPv4-mapped IPv6
@@ -1030,11 +1111,12 @@
  * @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;
@@ -1059,7 +1141,8 @@
     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;
@@ -1318,7 +1401,6 @@
         return -1;
 }
 
-
 /**
  * Join/Leave the nominated multicast group on the specified socket.
  * Implemented by setting the multicast 'add membership'/'drop membership'
@@ -1578,7 +1660,6 @@
     return sock;
 }
 
-
 static void osNetworkSystem_createStreamSocketImpl(JNIEnv* env, jclass clazz,
         jobject fileDescriptor, jboolean preferIPv4Stack) {
     // LOGD("ENTER createSocketImpl");
@@ -2336,7 +2417,7 @@
     }
 
     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);
@@ -3683,6 +3764,7 @@
     { "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) {
@@ -3691,3 +3773,4 @@
             gMethods,
             NELEM(gMethods));
 }
+// END android-changed
diff --git a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet4AddressTest.java b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet4AddressTest.java
index 920f137..163db31 100644
--- a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet4AddressTest.java
+++ b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet4AddressTest.java
@@ -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 @@
         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 @@
         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 @@
         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");
diff --git a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet6AddressTest.java b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet6AddressTest.java
index 62952d9..98ae45e 100644
--- a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet6AddressTest.java
+++ b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet6AddressTest.java
@@ -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 @@
         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 @@
         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 @@
                 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 @@
                 (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 @@
         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");
diff --git a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java
index 6087a46..5635ecb 100644
--- a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java
+++ b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java
@@ -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 @@
         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)