Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 419a4ce9 authored by Lorenzo Colitti's avatar Lorenzo Colitti
Browse files

Add stacked interfaces to LinkProperties.

Bug: 8276725
Change-Id: I2f592d4c690e9af0459ae742ab16107a10d89353
parent 41c9c8e5
Loading
Loading
Loading
Loading
+133 −6
Original line number Diff line number Diff line
@@ -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;
            }

+26 −0
Original line number Diff line number Diff line
@@ -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()));
        }
    }
}