RouteInfo changes.
- Add the interface name. - Fix a bug where a default route would match an address of another protocol (e.g., 0.0.0.0/0 would match 2001::). - Tweak the hashCode method. - Write a unit test. Change-Id: Ida8266de440a9b1d9eaa132f182b9f1ce8978c44
This commit is contained in:
@@ -92,6 +92,11 @@ public class LinkProperties implements Parcelable {
|
|||||||
|
|
||||||
public void setInterfaceName(String iface) {
|
public void setInterfaceName(String iface) {
|
||||||
mIfaceName = iface;
|
mIfaceName = iface;
|
||||||
|
ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size());
|
||||||
|
for (RouteInfo route : mRoutes) {
|
||||||
|
newRoutes.add(routeWithInterface(route));
|
||||||
|
}
|
||||||
|
mRoutes = newRoutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getInterfaceName() {
|
public String getInterfaceName() {
|
||||||
@@ -130,9 +135,25 @@ public class LinkProperties implements Parcelable {
|
|||||||
mDomains = domains;
|
mDomains = domains;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addRoute(RouteInfo route) {
|
private RouteInfo routeWithInterface(RouteInfo route) {
|
||||||
if (route != null) mRoutes.add(route);
|
return new RouteInfo(
|
||||||
|
route.getDestination(),
|
||||||
|
route.getGateway(),
|
||||||
|
mIfaceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addRoute(RouteInfo route) {
|
||||||
|
if (route != null) {
|
||||||
|
String routeIface = route.getInterface();
|
||||||
|
if (routeIface != null && !routeIface.equals(mIfaceName)) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Route added with non-matching interface: " + routeIface +
|
||||||
|
" vs. mIfaceName");
|
||||||
|
}
|
||||||
|
mRoutes.add(routeWithInterface(route));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Collection<RouteInfo> getRoutes() {
|
public Collection<RouteInfo> getRoutes() {
|
||||||
return Collections.unmodifiableCollection(mRoutes);
|
return Collections.unmodifiableCollection(mRoutes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,17 @@ import java.util.Collection;
|
|||||||
/**
|
/**
|
||||||
* A simple container for route information.
|
* A simple container for route information.
|
||||||
*
|
*
|
||||||
|
* In order to be used, a route must have a destination prefix and:
|
||||||
|
*
|
||||||
|
* - A gateway address (next-hop, for gatewayed routes), or
|
||||||
|
* - An interface (for directly-connected routes), or
|
||||||
|
* - Both a gateway and an interface.
|
||||||
|
*
|
||||||
|
* This class does not enforce these constraints because there is code that
|
||||||
|
* uses RouteInfo objects to store directly-connected routes without interfaces.
|
||||||
|
* Such objects cannot be used directly, but can be put into a LinkProperties
|
||||||
|
* object which then specifies the interface.
|
||||||
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public class RouteInfo implements Parcelable {
|
public class RouteInfo implements Parcelable {
|
||||||
@@ -42,10 +53,30 @@ public class RouteInfo implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
private final InetAddress mGateway;
|
private final InetAddress mGateway;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface for this route.
|
||||||
|
*/
|
||||||
|
private final String mInterface;
|
||||||
|
|
||||||
private final boolean mIsDefault;
|
private final boolean mIsDefault;
|
||||||
private final boolean mIsHost;
|
private final boolean mIsHost;
|
||||||
|
|
||||||
public RouteInfo(LinkAddress destination, InetAddress gateway) {
|
/**
|
||||||
|
* Constructs a RouteInfo object.
|
||||||
|
*
|
||||||
|
* If @destination is null, then @gateway must be specified and the
|
||||||
|
* constructed route is either the IPv4 default route <code>0.0.0.0</code>
|
||||||
|
* if @gateway is an instance of {@link Inet4Address}, or the IPv6 default
|
||||||
|
* route <code>::/0</code> if @gateway is an instance of
|
||||||
|
* {@link Inet6Address}.
|
||||||
|
*
|
||||||
|
* @destination and @gateway may not both be null.
|
||||||
|
*
|
||||||
|
* @param destination the destination prefix
|
||||||
|
* @param gateway the IP address to route packets through
|
||||||
|
* @param iface the interface name to send packets on
|
||||||
|
*/
|
||||||
|
public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
|
||||||
if (destination == null) {
|
if (destination == null) {
|
||||||
if (gateway != null) {
|
if (gateway != null) {
|
||||||
if (gateway instanceof Inet4Address) {
|
if (gateway instanceof Inet4Address) {
|
||||||
@@ -55,7 +86,8 @@ public class RouteInfo implements Parcelable {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// no destination, no gateway. invalid.
|
// no destination, no gateway. invalid.
|
||||||
throw new RuntimeException("Invalid arguments passed in.");
|
throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," +
|
||||||
|
destination);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (gateway == null) {
|
if (gateway == null) {
|
||||||
@@ -68,16 +100,21 @@ public class RouteInfo implements Parcelable {
|
|||||||
mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
|
mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
|
||||||
destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
|
destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
|
||||||
mGateway = gateway;
|
mGateway = gateway;
|
||||||
|
mInterface = iface;
|
||||||
mIsDefault = isDefault();
|
mIsDefault = isDefault();
|
||||||
mIsHost = isHost();
|
mIsHost = isHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RouteInfo(LinkAddress destination, InetAddress gateway) {
|
||||||
|
this(destination, gateway, null);
|
||||||
|
}
|
||||||
|
|
||||||
public RouteInfo(InetAddress gateway) {
|
public RouteInfo(InetAddress gateway) {
|
||||||
this(null, gateway);
|
this(null, gateway, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RouteInfo(LinkAddress host) {
|
public RouteInfo(LinkAddress host) {
|
||||||
this(host, null);
|
this(host, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RouteInfo makeHostRoute(InetAddress host) {
|
public static RouteInfo makeHostRoute(InetAddress host) {
|
||||||
@@ -119,6 +156,10 @@ public class RouteInfo implements Parcelable {
|
|||||||
return mGateway;
|
return mGateway;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getInterface() {
|
||||||
|
return mInterface;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isDefaultRoute() {
|
public boolean isDefaultRoute() {
|
||||||
return mIsDefault;
|
return mIsDefault;
|
||||||
}
|
}
|
||||||
@@ -153,6 +194,8 @@ public class RouteInfo implements Parcelable {
|
|||||||
dest.writeByte((byte) 1);
|
dest.writeByte((byte) 1);
|
||||||
dest.writeByteArray(mGateway.getAddress());
|
dest.writeByteArray(mGateway.getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dest.writeString(mInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -171,14 +214,19 @@ public class RouteInfo implements Parcelable {
|
|||||||
target.getGateway() == null
|
target.getGateway() == null
|
||||||
: mGateway.equals(target.getGateway());
|
: mGateway.equals(target.getGateway());
|
||||||
|
|
||||||
return sameDestination && sameAddress
|
boolean sameInterface = (mInterface == null) ?
|
||||||
|
target.getInterface() == null
|
||||||
|
: mInterface.equals(target.getInterface());
|
||||||
|
|
||||||
|
return sameDestination && sameAddress && sameInterface
|
||||||
&& mIsDefault == target.mIsDefault;
|
&& mIsDefault == target.mIsDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return (mDestination == null ? 0 : mDestination.hashCode())
|
return (mDestination == null ? 0 : mDestination.hashCode() * 41)
|
||||||
+ (mGateway == null ? 0 :mGateway.hashCode())
|
+ (mGateway == null ? 0 :mGateway.hashCode() * 47)
|
||||||
|
+ (mInterface == null ? 0 :mInterface.hashCode() * 67)
|
||||||
+ (mIsDefault ? 3 : 7);
|
+ (mIsDefault ? 3 : 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,13 +254,15 @@ public class RouteInfo implements Parcelable {
|
|||||||
} catch (UnknownHostException e) {}
|
} catch (UnknownHostException e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String iface = in.readString();
|
||||||
|
|
||||||
LinkAddress dest = null;
|
LinkAddress dest = null;
|
||||||
|
|
||||||
if (destAddr != null) {
|
if (destAddr != null) {
|
||||||
dest = new LinkAddress(destAddr, prefix);
|
dest = new LinkAddress(destAddr, prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RouteInfo(dest, gateway);
|
return new RouteInfo(dest, gateway, iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RouteInfo[] newArray(int size) {
|
public RouteInfo[] newArray(int size) {
|
||||||
@@ -220,13 +270,9 @@ public class RouteInfo implements Parcelable {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private boolean matches(InetAddress destination) {
|
protected boolean matches(InetAddress destination) {
|
||||||
if (destination == null) return false;
|
if (destination == null) return false;
|
||||||
|
|
||||||
// if the destination is present and the route is default.
|
|
||||||
// return true
|
|
||||||
if (isDefault()) return true;
|
|
||||||
|
|
||||||
// match the route destination and destination with prefix length
|
// match the route destination and destination with prefix length
|
||||||
InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
|
InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
|
||||||
mDestination.getNetworkPrefixLength());
|
mDestination.getNetworkPrefixLength());
|
||||||
|
|||||||
180
core/tests/coretests/src/android/net/RouteInfoTest.java
Normal file
180
core/tests/coretests/src/android/net/RouteInfoTest.java
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 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 java.lang.reflect.Method;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
|
import android.net.LinkAddress;
|
||||||
|
import android.net.RouteInfo;
|
||||||
|
import android.os.Parcel;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
|
|
||||||
|
public class RouteInfoTest extends TestCase {
|
||||||
|
|
||||||
|
private InetAddress Address(String addr) {
|
||||||
|
return InetAddress.parseNumericAddress(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinkAddress Prefix(String prefix) {
|
||||||
|
String[] parts = prefix.split("/");
|
||||||
|
return new LinkAddress(Address(parts[0]), Integer.parseInt(parts[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testConstructor() {
|
||||||
|
RouteInfo r;
|
||||||
|
|
||||||
|
// Invalid input.
|
||||||
|
try {
|
||||||
|
r = new RouteInfo(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);
|
||||||
|
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");
|
||||||
|
assertEquals(Prefix("0.0.0.0/0"), r.getDestination());
|
||||||
|
assertEquals(Address("192.0.2.1"), r.getGateway());
|
||||||
|
assertEquals("wlan0", r.getInterface());
|
||||||
|
|
||||||
|
// Null gateway sets gateway to unspecified address (why?).
|
||||||
|
r = new RouteInfo(Prefix("2001:db8:beef:cafe::/48"), null, "lo");
|
||||||
|
assertEquals(Prefix("2001:db8:beef::/48"), r.getDestination());
|
||||||
|
assertEquals(Address("::"), r.getGateway());
|
||||||
|
assertEquals("lo", r.getInterface());
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("192.0.2.5/24"), null);
|
||||||
|
assertEquals(Prefix("192.0.2.0/24"), r.getDestination());
|
||||||
|
assertEquals(Address("0.0.0.0"), r.getGateway());
|
||||||
|
assertNull(r.getInterface());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMatches() {
|
||||||
|
class PatchedRouteInfo extends RouteInfo {
|
||||||
|
public PatchedRouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
|
||||||
|
super(destination, gateway, iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(InetAddress destination) {
|
||||||
|
return super.matches(destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RouteInfo r;
|
||||||
|
|
||||||
|
r = new PatchedRouteInfo(Prefix("2001:db8:f00::ace:d00d/127"), null, "rmnet0");
|
||||||
|
assertTrue(r.matches(Address("2001:db8:f00::ace:d00c")));
|
||||||
|
assertTrue(r.matches(Address("2001:db8:f00::ace:d00d")));
|
||||||
|
assertFalse(r.matches(Address("2001:db8:f00::ace:d00e")));
|
||||||
|
assertFalse(r.matches(Address("2001:db8:f00::bad:d00d")));
|
||||||
|
assertFalse(r.matches(Address("2001:4868:4860::8888")));
|
||||||
|
|
||||||
|
r = new PatchedRouteInfo(Prefix("192.0.2.0/23"), null, "wlan0");
|
||||||
|
assertTrue(r.matches(Address("192.0.2.43")));
|
||||||
|
assertTrue(r.matches(Address("192.0.3.21")));
|
||||||
|
assertFalse(r.matches(Address("192.0.0.21")));
|
||||||
|
assertFalse(r.matches(Address("8.8.8.8")));
|
||||||
|
|
||||||
|
RouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0");
|
||||||
|
assertTrue(ipv6Default.matches(Address("2001:db8::f00")));
|
||||||
|
assertFalse(ipv6Default.matches(Address("192.0.2.1")));
|
||||||
|
|
||||||
|
RouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0");
|
||||||
|
assertTrue(ipv4Default.matches(Address("255.255.255.255")));
|
||||||
|
assertTrue(ipv4Default.matches(Address("192.0.2.1")));
|
||||||
|
assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertAreEqual(Object o1, Object o2) {
|
||||||
|
assertTrue(o1.equals(o2));
|
||||||
|
assertTrue(o2.equals(o1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertAreNotEqual(Object o1, Object o2) {
|
||||||
|
assertFalse(o1.equals(o2));
|
||||||
|
assertFalse(o2.equals(o1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEquals() {
|
||||||
|
// IPv4
|
||||||
|
RouteInfo r1 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
|
||||||
|
RouteInfo r2 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
|
||||||
|
assertAreEqual(r1, r2);
|
||||||
|
|
||||||
|
RouteInfo r3 = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "wlan0");
|
||||||
|
RouteInfo r4 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::2"), "wlan0");
|
||||||
|
RouteInfo r5 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "rmnet0");
|
||||||
|
assertAreNotEqual(r1, r3);
|
||||||
|
assertAreNotEqual(r1, r4);
|
||||||
|
assertAreNotEqual(r1, r5);
|
||||||
|
|
||||||
|
// IPv6
|
||||||
|
r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
|
||||||
|
r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
|
||||||
|
assertAreEqual(r1, r2);
|
||||||
|
|
||||||
|
r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
|
||||||
|
r4 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.2"), "wlan0");
|
||||||
|
r5 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "rmnet0");
|
||||||
|
assertAreNotEqual(r1, r3);
|
||||||
|
assertAreNotEqual(r1, r4);
|
||||||
|
assertAreNotEqual(r1, r5);
|
||||||
|
|
||||||
|
// Interfaces (but not destinations or gateways) can be null.
|
||||||
|
r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
|
||||||
|
r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
|
||||||
|
r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
|
||||||
|
assertAreEqual(r1, r2);
|
||||||
|
assertAreNotEqual(r1, r3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteInfo passThroughParcel(RouteInfo r) {
|
||||||
|
Parcel p = Parcel.obtain();
|
||||||
|
RouteInfo r2 = null;
|
||||||
|
try {
|
||||||
|
r.writeToParcel(p, 0);
|
||||||
|
p.setDataPosition(0);
|
||||||
|
r2 = RouteInfo.CREATOR.createFromParcel(p);
|
||||||
|
} finally {
|
||||||
|
p.recycle();
|
||||||
|
}
|
||||||
|
assertNotNull(r2);
|
||||||
|
return r2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void assertParcelingIsLossless(RouteInfo r) {
|
||||||
|
RouteInfo r2 = passThroughParcel(r);
|
||||||
|
assertEquals(r, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testParceling() {
|
||||||
|
RouteInfo r;
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("::/0"), Address("2001:db8::"), null);
|
||||||
|
assertParcelingIsLossless(r);
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
|
||||||
|
assertParcelingIsLossless(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user