From 1b4ca183763171fdd5228d6184ad77a61046bbea Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 18 Sep 2009 15:25:06 -0700 Subject: [PATCH] Manual merge of change I3665f82b into master. --- .../luni/src/main/java/java/net/InetAddress.java | 183 +-------------- .../harmony/luni/platform/INetworkSystem.java | 5 + .../harmony/luni/platform/OSNetworkSystem.java | 3 + .../org/apache/harmony/luni/util/Inet6Util.java | 238 ------------------- ...pache_harmony_luni_platform_OSNetworkSystem.cpp | 259 ++++++++++++++++----- .../luni/tests/java/net/Inet4AddressTest.java | 9 - .../luni/tests/java/net/Inet6AddressTest.java | 17 +- .../luni/tests/java/net/InetAddressTest.java | 7 - 8 files changed, 224 insertions(+), 497 deletions(-) diff --git a/libcore/luni/src/main/java/java/net/InetAddress.java b/libcore/luni/src/main/java/java/net/InetAddress.java index 0fa4796dd..33c25f353 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 @@ 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 hexStrings = new ArrayList(); - ArrayList decStrings = new ArrayList(); - 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( "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 13453417c..fb47f0d9b 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 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 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 0fa25eaae..bd6a6097d 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 @@ 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, 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 4dae1c3d9..55914de92 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 @@ 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 hexStrings = new ArrayList(); - ArrayList decStrings = new ArrayList(); - 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 6d258e044..dd964983a 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 #include #include +#include #include #include #include @@ -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(&(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(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 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 920f1377e..163db31f0 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 @@ 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"); 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 62952d998..98ae45e13 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 @@ 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"); 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 6087a4609..5635ecb76 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 @@ 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) -- 2.11.0