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)