Add stacked interfaces to LinkProperties.

Bug: 8276725
Change-Id: I2f592d4c690e9af0459ae742ab16107a10d89353
This commit is contained in:
Lorenzo Colitti
2013-03-07 10:59:25 -08:00
parent 24efb41874
commit c080312552
2 changed files with 159 additions and 6 deletions

View File

@@ -23,10 +23,13 @@ import android.text.TextUtils;
import android.util.Log;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Hashtable;
/**
* Describes the properties of a network link.
@@ -48,10 +51,15 @@ import java.util.Collections;
* don't care which is used. The gateways will be
* selected based on the destination address and the
* source address has no relavence.
*
* Links can also be stacked on top of each other.
* This can be used, for example, to represent a tunnel
* interface that runs on top of a physical interface.
*
* @hide
*/
public class LinkProperties implements Parcelable {
// The interface described by the network link.
private String mIfaceName;
private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
private Collection<InetAddress> mDnses = new ArrayList<InetAddress>();
@@ -60,6 +68,11 @@ public class LinkProperties implements Parcelable {
private ProxyProperties mHttpProxy;
public boolean mLogMe;
// Stores the properties of links that are "stacked" above this link.
// Indexed by interface name to allow modification and to prevent duplicates being added.
private Hashtable<String, LinkProperties> mStackedLinks =
new Hashtable<String, LinkProperties>();
public static class CompareResult<T> {
public Collection<T> removed = new ArrayList<T>();
public Collection<T> added = new ArrayList<T>();
@@ -90,6 +103,9 @@ public class LinkProperties implements Parcelable {
for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
mHttpProxy = (source.getHttpProxy() == null) ?
null : new ProxyProperties(source.getHttpProxy());
for (LinkProperties l: source.mStackedLinks.values()) {
addStackedLink(l);
}
}
}
@@ -165,10 +181,25 @@ public class LinkProperties implements Parcelable {
}
}
/**
* Returns all the routes on this link.
*/
public Collection<RouteInfo> getRoutes() {
return Collections.unmodifiableCollection(mRoutes);
}
/**
* Returns all the routes on this link and all the links stacked above it.
*/
public Collection<RouteInfo> getAllRoutes() {
Collection<RouteInfo> routes = new ArrayList();
routes.addAll(mRoutes);
for (LinkProperties stacked: mStackedLinks.values()) {
routes.addAll(stacked.getAllRoutes());
}
return Collections.unmodifiableCollection(routes);
}
public void setHttpProxy(ProxyProperties proxy) {
mHttpProxy = proxy;
}
@@ -176,6 +207,46 @@ public class LinkProperties implements Parcelable {
return mHttpProxy;
}
/**
* Adds a stacked link.
*
* If there is already a stacked link with the same interfacename as link,
* that link is replaced with link. Otherwise, link is added to the list
* of stacked links. If link is null, nothing changes.
*
* @param link The link to add.
*/
public void addStackedLink(LinkProperties link) {
if (link != null && link.getInterfaceName() != null) {
mStackedLinks.put(link.getInterfaceName(), link);
}
}
/**
* Removes a stacked link.
*
* If there a stacked link with the same interfacename as link, it is
* removed. Otherwise, nothing changes.
*
* @param link The link to add.
*/
public void removeStackedLink(LinkProperties link) {
if (link != null && link.getInterfaceName() != null) {
mStackedLinks.remove(link.getInterfaceName());
}
}
/**
* Returns all the links stacked on top of this link.
*/
public Collection<LinkProperties> getStackedLinks() {
Collection<LinkProperties> stacked = new ArrayList<LinkProperties>();
for (LinkProperties link : mStackedLinks.values()) {
stacked.add(new LinkProperties(link));
}
return Collections.unmodifiableCollection(stacked);
}
public void clear() {
if (mLogMe) {
Log.d("LinkProperties", "clear from " + mIfaceName);
@@ -190,6 +261,7 @@ public class LinkProperties implements Parcelable {
mDomains = null;
mRoutes.clear();
mHttpProxy = null;
mStackedLinks.clear();
}
/**
@@ -219,7 +291,29 @@ public class LinkProperties implements Parcelable {
routes += "] ";
String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
return ifaceName + linkAddresses + routes + dns + domainName + proxy;
String stacked = "";
if (mStackedLinks.values().size() > 0) {
stacked += " Stacked: [";
for (LinkProperties link: mStackedLinks.values()) {
stacked += " [" + link.toString() + " ],";
}
stacked += "] ";
}
return ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked;
}
/**
* Returns true if this link has an IPv4 address.
*
* @return {@code true} if there is an IPv4 address, {@code false} otherwise.
*/
public boolean hasIPv4Address() {
for (LinkAddress address : mLinkAddresses) {
if (address.getAddress() instanceof Inet4Address) {
return true;
}
}
return false;
}
/**
@@ -286,6 +380,26 @@ public class LinkProperties implements Parcelable {
getHttpProxy().equals(target.getHttpProxy());
}
/**
* Compares this {@code LinkProperties} stacked links against the target
*
* @param target LinkProperties to compare.
* @return {@code true} if both are identical, {@code false} otherwise.
*/
public boolean isIdenticalStackedLinks(LinkProperties target) {
if (!mStackedLinks.keys().equals(target.mStackedLinks.keys())) {
return false;
}
for (LinkProperties stacked : mStackedLinks.values()) {
// Hashtable values can never be null.
String iface = stacked.getInterfaceName();
if (!stacked.equals(target.mStackedLinks.get(iface))) {
return false;
}
}
return true;
}
@Override
/**
* Compares this {@code LinkProperties} instance against the target
@@ -298,6 +412,10 @@ public class LinkProperties implements Parcelable {
* 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
* 2. Worst case performance is O(n^2).
*
* This method does not check that stacked interfaces are equal, because
* stacked interfaces are not so much a property of the link as a
* description of connections between links.
*
* @param obj the object to be tested for equality.
* @return {@code true} if both objects are equal, {@code false} otherwise.
*/
@@ -312,7 +430,8 @@ public class LinkProperties implements Parcelable {
isIdenticalAddresses(target) &&
isIdenticalDnses(target) &&
isIdenticalRoutes(target) &&
isIdenticalHttpProxy(target);
isIdenticalHttpProxy(target) &&
isIdenticalStackedLinks(target);
}
/**
@@ -394,10 +513,10 @@ public class LinkProperties implements Parcelable {
*/
CompareResult<RouteInfo> result = new CompareResult<RouteInfo>();
result.removed = new ArrayList<RouteInfo>(mRoutes);
result.removed = getAllRoutes();
result.added.clear();
if (target != null) {
for (RouteInfo r : target.getRoutes()) {
for (RouteInfo r : target.getAllRoutes()) {
if (! result.removed.remove(r)) {
result.added.add(r);
}
@@ -419,7 +538,8 @@ public class LinkProperties implements Parcelable {
+ mDnses.size() * 37
+ ((null == mDomains) ? 0 : mDomains.hashCode())
+ mRoutes.size() * 41
+ ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()));
+ ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
+ mStackedLinks.hashCode() * 47);
}
/**
@@ -449,6 +569,8 @@ public class LinkProperties implements Parcelable {
} else {
dest.writeByte((byte)0);
}
ArrayList<LinkProperties> stackedLinks = new ArrayList(mStackedLinks.values());
dest.writeList(stackedLinks);
}
/**
@@ -481,6 +603,11 @@ public class LinkProperties implements Parcelable {
if (in.readByte() == 1) {
netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
}
ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
in.readList(stackedLinks, LinkProperties.class.getClassLoader());
for (LinkProperties stackedLink: stackedLinks) {
netProp.addStackedLink(stackedLink);
}
return netProp;
}

View File

@@ -22,6 +22,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.TestCase;
import java.net.InetAddress;
import java.util.ArrayList;
public class LinkPropertiesTest extends TestCase {
private static String ADDRV4 = "75.208.6.1";
@@ -255,5 +256,30 @@ public class LinkPropertiesTest extends TestCase {
assertAllRoutesHaveInterface("p2p0", lp2);
assertEquals(3, lp.compareRoutes(lp2).added.size());
assertEquals(3, lp.compareRoutes(lp2).removed.size());
@SmallTest
public void testStackedInterfaces() {
LinkProperties rmnet0 = new LinkProperties();
rmnet0.setInterfaceName("rmnet0");
LinkProperties clat4 = new LinkProperties();
clat4.setInterfaceName("clat4");
assertEquals(0, rmnet0.getStackedLinks().size());
rmnet0.addStackedLink(clat4);
assertEquals(1, rmnet0.getStackedLinks().size());
rmnet0.addStackedLink(clat4);
assertEquals(1, rmnet0.getStackedLinks().size());
assertEquals(0, clat4.getStackedLinks().size());
// Modify an item in the returned collection to see what happens.
for (LinkProperties link : rmnet0.getStackedLinks()) {
if (link.getInterfaceName().equals("clat4")) {
link.setInterfaceName("newname");
}
}
for (LinkProperties link : rmnet0.getStackedLinks()) {
assertFalse("newname".equals(link.getInterfaceName()));
}
}
}