Add a new IpPrefix class and use it in RouteInfo. am: 8162a5ef8b
Original change: undetermined
Change-Id: Ibf58069e6536618eee575da33ab0d46e248d8625
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
new file mode 100644
index 0000000..dfe0384
--- /dev/null
+++ b/core/java/android/net/IpPrefix.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
+/**
+ * This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a
+ * power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of
+ * information:
+ *
+ * <ul>
+ * <li>A starting IP address (IPv4 or IPv6). This is the first IP address of the prefix.
+ * <li>A prefix length. This specifies the length of the prefix by specifing the number of bits
+ * in the IP address, starting from the most significant bit in network byte order, that
+ * are constant for all addresses in the prefix.
+ * </ul>
+ *
+ * For example, the prefix <code>192.0.2.0/24</code> covers the 256 IPv4 addresses from
+ * <code>192.0.2.0</code> to <code>192.0.2.255</code>, inclusive, and the prefix
+ * <code>2001:db8:1:2</code> covers the 2^64 IPv6 addresses from <code>2001:db8:1:2::</code> to
+ * <code>2001:db8:1:2:ffff:ffff:ffff:ffff</code>, inclusive.
+ *
+ * Objects of this class are immutable.
+ */
+public class IpPrefix implements Parcelable {
+ private final byte[] address; // network byte order
+ private final int prefixLength;
+
+ /**
+ * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in
+ * network byte order and a prefix length.
+ *
+ * @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).
+ *
+ * @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
+ }
+
+ /**
+ * @hide
+ */
+ public IpPrefix(InetAddress address, int prefixLength) {
+ this(address.getAddress(), prefixLength);
+ }
+
+ /**
+ * Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two
+ * objects are equal if they have the same startAddress and prefixLength.
+ *
+ * @param obj the object to be tested for equality.
+ * @return {@code true} if both objects are equal, {@code false} otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof IpPrefix)) {
+ return false;
+ }
+ IpPrefix that = (IpPrefix) obj;
+ return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength;
+ }
+
+ /**
+ * Gets the hashcode of the represented IP prefix.
+ *
+ * @return the appropriate hashcode value.
+ */
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(address) + 11 * prefixLength;
+ }
+
+ /**
+ * Returns a copy of the first IP address in the prefix. Modifying the returned object does not
+ * change this object's contents.
+ *
+ * @return the address in the form of a byte array.
+ */
+ public InetAddress getAddress() {
+ try {
+ return InetAddress.getByAddress(address);
+ } catch (UnknownHostException e) {
+ // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte
+ // array is the wrong length, but we check that in the constructor.
+ return null;
+ }
+ }
+
+ /**
+ * Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth
+ * element). Modifying the returned array does not change this object's contents.
+ *
+ * @return the address in the form of a byte array.
+ */
+ public byte[] getRawAddress() {
+ return address.clone();
+ }
+
+ /**
+ * Returns the prefix length of this {@code IpAddress}.
+ *
+ * @return the prefix length.
+ */
+ public int getPrefixLength() {
+ return prefixLength;
+ }
+
+ /**
+ * Implement the Parcelable interface.
+ * @hide
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Implement the Parcelable interface.
+ * @hide
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByteArray(address);
+ dest.writeInt(prefixLength);
+ }
+
+ /**
+ * Implement the Parcelable interface.
+ * @hide
+ */
+ public static final Creator<IpPrefix> CREATOR =
+ new Creator<IpPrefix>() {
+ public IpPrefix createFromParcel(Parcel in) {
+ byte[] address = in.createByteArray();
+ int prefixLength = in.readInt();
+ return new IpPrefix(address, prefixLength);
+ }
+
+ public IpPrefix[] newArray(int size) {
+ return new IpPrefix[size];
+ }
+ };
+}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index cff9025..bb05936 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -77,9 +77,15 @@
}
}
+ /**
+ * @hide
+ */
public LinkProperties() {
}
+ /**
+ * @hide
+ */
public LinkProperties(LinkProperties source) {
if (source != null) {
mIfaceName = source.getInterfaceName();
@@ -267,7 +273,7 @@
}
/**
- * Returns all the {@link LinkAddress} for DNS servers on this link.
+ * Returns all the {@link InetAddress} for DNS servers on this link.
*
* @return An umodifiable {@link List} of {@link InetAddress} for DNS servers on
* this link.
@@ -477,12 +483,12 @@
String domainName = "Domains: " + mDomains;
- String mtu = "MTU: " + mMtu;
+ String mtu = " MTU: " + mMtu;
String routes = " Routes: [";
for (RouteInfo route : mRoutes) routes += route.toString() + ",";
routes += "] ";
- String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
+ String proxy = (mHttpProxy == null ? "" : " HttpProxy: " + mHttpProxy.toString() + " ");
String stacked = "";
if (mStackedLinks.values().size() > 0) {
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index ad8e4f7..a65523b 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -35,10 +35,10 @@
*
* A route contains three pieces of information:
* <ul>
- * <li>a destination {@link LinkAddress} for directly-connected subnets. If this is
- * {@code null} it indicates a default route of the address family (IPv4 or IPv6)
+ * <li>a destination {@link IpPrefix} specifying the network destinations covered by this route.
+ * If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6)
* implied by the gateway IP address.
- * <li>a gateway {@link InetAddress} for default routes. If this is {@code null} it
+ * <li>a gateway {@link InetAddress} indicating the next hop to use. If this is {@code null} it
* indicates a directly-connected route.
* <li>an interface (which may be unspecified).
* </ul>
@@ -49,6 +49,7 @@
public class RouteInfo implements Parcelable {
/**
* The IP destination address for this route.
+ * TODO: Make this an IpPrefix.
*/
private final LinkAddress mDestination;
@@ -80,6 +81,19 @@
* @param destination the destination prefix
* @param gateway the IP address to route packets through
* @param iface the interface name to send packets on
+ *
+ * TODO: Convert to use IpPrefix.
+ *
+ * @hide
+ */
+ public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) {
+ this(destination == null ? null :
+ new LinkAddress(destination.getAddress(), destination.getPrefixLength()),
+ gateway, iface);
+ }
+
+ /**
+ * @hide
*/
public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
if (destination == null) {
@@ -128,8 +142,17 @@
* <p>
* Destination and gateway may not both be null.
*
- * @param destination the destination address and prefix in a {@link LinkAddress}
+ * @param destination the destination address and prefix in an {@link IpPrefix}
* @param gateway the {@link InetAddress} to route packets through
+ *
+ * @hide
+ */
+ public RouteInfo(IpPrefix destination, InetAddress gateway) {
+ this(destination, gateway, null);
+ }
+
+ /**
+ * @hide
*/
public RouteInfo(LinkAddress destination, InetAddress gateway) {
this(destination, gateway, null);
@@ -139,16 +162,27 @@
* Constructs a default {@code RouteInfo} object.
*
* @param gateway the {@link InetAddress} to route packets through
+ *
+ * @hide
*/
public RouteInfo(InetAddress gateway) {
- this(null, gateway, null);
+ this((LinkAddress) null, gateway, null);
}
/**
* Constructs a {@code RouteInfo} object representing a direct connected subnet.
*
- * @param destination the {@link LinkAddress} describing the address and prefix
+ * @param destination the {@link IpPrefix} describing the address and prefix
* length of the subnet.
+ *
+ * @hide
+ */
+ public RouteInfo(IpPrefix destination) {
+ this(destination, null, null);
+ }
+
+ /**
+ * @hide
*/
public RouteInfo(LinkAddress destination) {
this(destination, null, null);
@@ -194,11 +228,19 @@
}
/**
- * Retrieves the destination address and prefix length in the form of a {@link LinkAddress}.
+ * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}.
*
- * @return {@link LinkAddress} specifying the destination. This is never {@code null}.
+ * @return {@link IpPrefix} specifying the destination. This is never {@code null}.
*/
- public LinkAddress getDestination() {
+ public IpPrefix getDestination() {
+ return new IpPrefix(mDestination.getAddress(), mDestination.getPrefixLength());
+ }
+
+ /**
+ * TODO: Convert callers to use IpPrefix and then remove.
+ * @hide
+ */
+ public LinkAddress getDestinationLinkAddress() {
return mDestination;
}
@@ -233,7 +275,8 @@
/**
* Indicates if this route is a host route (ie, matches only a single host address).
*
- * @return {@code true} if the destination has a prefix length of 32/128 for v4/v6.
+ * @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6,
+ * respectively.
* @hide
*/
public boolean isHostRoute() {
@@ -295,13 +338,22 @@
return bestRoute;
}
+ /**
+ * Returns a human-readable description of this object.
+ */
public String toString() {
String val = "";
if (mDestination != null) val = mDestination.toString();
- if (mGateway != null) val += " -> " + mGateway.getHostAddress();
+ val += " ->";
+ if (mGateway != null) val += " " + mGateway.getHostAddress();
+ if (mInterface != null) val += " " + mInterface;
return val;
}
+ /**
+ * Compares this RouteInfo object against the specified object and indicates if they are equal.
+ * @return {@code true} if the objects are equal, {@code false} otherwise.
+ */
public boolean equals(Object obj) {
if (this == obj) return true;
@@ -314,6 +366,9 @@
Objects.equals(mInterface, target.getInterface());
}
+ /**
+ * Returns a hashcode for this <code>RouteInfo</code> object.
+ */
public int hashCode() {
return (mDestination == null ? 0 : mDestination.hashCode() * 41)
+ (mGateway == null ? 0 :mGateway.hashCode() * 47)
diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java
index 55d6592..01283a6 100644
--- a/core/tests/coretests/src/android/net/RouteInfoTest.java
+++ b/core/tests/coretests/src/android/net/RouteInfoTest.java
@@ -43,17 +43,17 @@
// Invalid input.
try {
- r = new RouteInfo(null, null, "rmnet0");
+ r = new RouteInfo((LinkAddress) null, null, "rmnet0");
fail("Expected RuntimeException: destination and gateway null");
} catch(RuntimeException e) {}
// Null destination is default route.
- r = new RouteInfo(null, Address("2001:db8::1"), null);
+ r = new RouteInfo((LinkAddress) null, Address("2001:db8::1"), null);
assertEquals(Prefix("::/0"), r.getDestination());
assertEquals(Address("2001:db8::1"), r.getGateway());
assertNull(r.getInterface());
- r = new RouteInfo(null, Address("192.0.2.1"), "wlan0");
+ r = new RouteInfo((LinkAddress) null, Address("192.0.2.1"), "wlan0");
assertEquals(Prefix("0.0.0.0/0"), r.getDestination());
assertEquals(Address("192.0.2.1"), r.getGateway());
assertEquals("wlan0", r.getInterface());
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4c594e1..25e7822 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1871,7 +1871,7 @@
mNetd.addRoute(netId, r);
}
if (exempt) {
- LinkAddress dest = r.getDestination();
+ LinkAddress dest = r.getDestinationLinkAddress();
if (!mExemptAddresses.contains(dest)) {
mNetd.setHostExemption(dest);
mExemptAddresses.add(dest);
@@ -1904,7 +1904,7 @@
} else {
mNetd.removeRoute(netId, r);
}
- LinkAddress dest = r.getDestination();
+ LinkAddress dest = r.getDestinationLinkAddress();
if (mExemptAddresses.contains(dest)) {
mNetd.clearHostExemption(dest);
mExemptAddresses.remove(dest);