diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2014-06-12 13:41:17 +0900 |
---|---|---|
committer | Lorenzo Colitti <lorenzo@google.com> | 2014-06-17 11:18:53 +0900 |
commit | 8c6c2c3c929acad783b9a56b8d9efa597d0ae609 (patch) | |
tree | de082b0ae0e84c7aa46ed149911a9371216273e0 /core/java/android/net | |
parent | 97df96d8ebabd437db6a7691b8260bd51cf7f8d5 (diff) | |
download | frameworks_base-8c6c2c3c929acad783b9a56b8d9efa597d0ae609.zip frameworks_base-8c6c2c3c929acad783b9a56b8d9efa597d0ae609.tar.gz frameworks_base-8c6c2c3c929acad783b9a56b8d9efa597d0ae609.tar.bz2 |
IpPrefix improvements.
1. Allow IpPrefixes to be created from strings. In order to do
this, factor out the code from LinkAddress which already does
this to a small utility class in NetworkUtils.
2. Truncate prefixes on creation, fixing a TODO.
3. Add a toString method.
4. Write a unit test.
While I'm at it, make RouteInfoTest pass again, and convert it
to use IpPrefix instead of LinkAddress.
Change-Id: I5f68f8af8f4aedb25afaee00e05369f01e82a70b
Diffstat (limited to 'core/java/android/net')
-rw-r--r-- | core/java/android/net/IpPrefix.java | 70 | ||||
-rw-r--r-- | core/java/android/net/LinkAddress.java | 21 | ||||
-rw-r--r-- | core/java/android/net/NetworkUtils.java | 55 |
3 files changed, 104 insertions, 42 deletions
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java index a14d13f..f1fa3eb 100644 --- a/core/java/android/net/IpPrefix.java +++ b/core/java/android/net/IpPrefix.java @@ -18,6 +18,7 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; +import android.util.Pair; import java.net.InetAddress; import java.net.UnknownHostException; @@ -46,9 +47,18 @@ public final class IpPrefix implements Parcelable { private final byte[] address; // network byte order private final int prefixLength; + private void checkAndMaskAddressAndPrefixLength() { + if (address.length != 4 && address.length != 16) { + throw new IllegalArgumentException( + "IpPrefix has " + address.length + " bytes which is neither 4 nor 16"); + } + NetworkUtils.maskRawAddress(address, prefixLength); + } + /** * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in - * network byte order and a prefix length. + * network byte order and a prefix length. Silently truncates the address to the prefix length, + * so for example {@code 192.0.2.1/24} is silently converted to {@code 192.0.2.0/24}. * * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long. * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). @@ -56,24 +66,46 @@ public final class IpPrefix implements Parcelable { * @hide */ public IpPrefix(byte[] address, int prefixLength) { - if (address.length != 4 && address.length != 16) { - throw new IllegalArgumentException( - "IpPrefix has " + address.length + " bytes which is neither 4 nor 16"); - } - if (prefixLength < 0 || prefixLength > (address.length * 8)) { - throw new IllegalArgumentException("IpPrefix with " + address.length + - " bytes has invalid prefix length " + prefixLength); - } this.address = address.clone(); this.prefixLength = prefixLength; - // TODO: Validate that the non-prefix bits are zero + checkAndMaskAddressAndPrefixLength(); } /** + * Constructs a new {@code IpPrefix} from an IPv4 or IPv6 address and a prefix length. Silently + * truncates the address to the prefix length, so for example {@code 192.0.2.1/24} is silently + * converted to {@code 192.0.2.0/24}. + * + * @param address the IP address. Must be non-null. + * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). * @hide */ public IpPrefix(InetAddress address, int prefixLength) { - this(address.getAddress(), prefixLength); + // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array, + // which is unnecessary because getAddress() already returns a clone. + this.address = address.getAddress(); + this.prefixLength = prefixLength; + checkAndMaskAddressAndPrefixLength(); + } + + /** + * Constructs a new IpPrefix from a string such as "192.0.2.1/24" or "2001:db8::1/64". + * Silently truncates the address to the prefix length, so for example {@code 192.0.2.1/24} + * is silently converted to {@code 192.0.2.0/24}. + * + * @param prefix the prefix to parse + * + * @hide + */ + public IpPrefix(String prefix) { + // We don't reuse the (InetAddress, int) constructor because "error: call to this must be + // first statement in constructor". We could factor out setting the member variables to an + // init() method, but if we did, then we'd have to make the members non-final, or "error: + // cannot assign a value to final variable address". So we just duplicate the code here. + Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(prefix); + this.address = ipAndMask.first.getAddress(); + this.prefixLength = ipAndMask.second; + checkAndMaskAddressAndPrefixLength(); } /** @@ -129,7 +161,7 @@ public final class IpPrefix implements Parcelable { } /** - * Returns the prefix length of this {@code IpAddress}. + * Returns the prefix length of this {@code IpPrefix}. * * @return the prefix length. */ @@ -138,6 +170,20 @@ public final class IpPrefix implements Parcelable { } /** + * Returns a string representation of this {@code IpPrefix}. + * + * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::"}. + */ + public String toString() { + try { + return InetAddress.getByAddress(address).getHostAddress() + "/" + prefixLength; + } catch(UnknownHostException e) { + // Cosmic rays? + throw new IllegalStateException("IpPrefix with invalid address! Shouldn't happen.", e); + } + } + + /** * Implement the Parcelable interface. */ public int describeContents() { diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index 5246078..f9a25f9 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -18,6 +18,7 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; +import android.util.Pair; import java.net.Inet4Address; import java.net.InetAddress; @@ -166,23 +167,9 @@ public class LinkAddress implements Parcelable { * @hide */ public LinkAddress(String address, int flags, int scope) { - InetAddress inetAddress = null; - int prefixLength = -1; - try { - String [] pieces = address.split("/", 2); - prefixLength = Integer.parseInt(pieces[1]); - inetAddress = InetAddress.parseNumericAddress(pieces[0]); - } catch (NullPointerException e) { // Null string. - } catch (ArrayIndexOutOfBoundsException e) { // No prefix length. - } catch (NumberFormatException e) { // Non-numeric prefix. - } catch (IllegalArgumentException e) { // Invalid IP address. - } - - if (inetAddress == null || prefixLength == -1) { - throw new IllegalArgumentException("Bad LinkAddress params " + address); - } - - init(inetAddress, prefixLength, flags, scope); + // This may throw an IllegalArgumentException; catching it is the caller's responsibility. + Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address); + init(ipAndMask.first, ipAndMask.second, flags, scope); } /** diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index b02f88e..15c0a71 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -24,6 +24,8 @@ import java.util.Collection; import java.util.Locale; import android.util.Log; +import android.util.Pair; + /** * Native methods for managing network interfaces. @@ -218,24 +220,17 @@ public class NetworkUtils { } /** - * Get InetAddress masked with prefixLength. Will never return null. - * @param IP address which will be masked with specified prefixLength - * @param prefixLength the prefixLength used to mask the IP + * Masks a raw IP address byte array with the specified prefix length. */ - public static InetAddress getNetworkPart(InetAddress address, int prefixLength) { - if (address == null) { - throw new RuntimeException("getNetworkPart doesn't accept null address"); - } - - byte[] array = address.getAddress(); - + public static void maskRawAddress(byte[] array, int prefixLength) { if (prefixLength < 0 || prefixLength > array.length * 8) { - throw new RuntimeException("getNetworkPart - bad prefixLength"); + throw new RuntimeException("IP address with " + array.length + + " bytes has invalid prefix length " + prefixLength); } int offset = prefixLength / 8; - int reminder = prefixLength % 8; - byte mask = (byte)(0xFF << (8 - reminder)); + int remainder = prefixLength % 8; + byte mask = (byte)(0xFF << (8 - remainder)); if (offset < array.length) array[offset] = (byte)(array[offset] & mask); @@ -244,6 +239,16 @@ public class NetworkUtils { for (; offset < array.length; offset++) { array[offset] = 0; } + } + + /** + * Get InetAddress masked with prefixLength. Will never return null. + * @param address the IP address to mask with + * @param prefixLength the prefixLength used to mask the IP + */ + public static InetAddress getNetworkPart(InetAddress address, int prefixLength) { + byte[] array = address.getAddress(); + maskRawAddress(array, prefixLength); InetAddress netPart = null; try { @@ -255,6 +260,30 @@ public class NetworkUtils { } /** + * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64". + * @hide + */ + public static Pair<InetAddress, Integer> parseIpAndMask(String ipAndMaskString) { + InetAddress address = null; + int prefixLength = -1; + try { + String[] pieces = ipAndMaskString.split("/", 2); + prefixLength = Integer.parseInt(pieces[1]); + address = InetAddress.parseNumericAddress(pieces[0]); + } catch (NullPointerException e) { // Null string. + } catch (ArrayIndexOutOfBoundsException e) { // No prefix length. + } catch (NumberFormatException e) { // Non-numeric prefix. + } catch (IllegalArgumentException e) { // Invalid IP address. + } + + if (address == null || prefixLength == -1) { + throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString); + } + + return new Pair<InetAddress, Integer>(address, prefixLength); + } + + /** * Check if IP address type is consistent between two InetAddress. * @return true if both are the same type. False otherwise. */ |