LinkProperties.java revision 15bc62fe205b755582845829821373985efc60af
147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt/*
26e80997a9a7b6a15370544edde322cd8833e9524Wink Saville * Copyright (C) 2010 The Android Open Source Project
347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt *
447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * Licensed under the Apache License, Version 2.0 (the "License");
547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * you may not use this file except in compliance with the License.
647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * You may obtain a copy of the License at
747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt *
847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt *      http://www.apache.org/licenses/LICENSE-2.0
947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt *
1047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * Unless required by applicable law or agreed to in writing, software
1147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * distributed under the License is distributed on an "AS IS" BASIS,
1247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * See the License for the specific language governing permissions and
1447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * limitations under the License.
1547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt */
1647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
1747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltpackage android.net;
1847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
1937e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwaltimport android.net.ProxyProperties;
2047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltimport android.os.Parcelable;
2147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltimport android.os.Parcel;
224e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wangimport android.text.TextUtils;
2347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
2447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltimport java.net.InetAddress;
25419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colittiimport java.net.Inet4Address;
26419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti
2747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltimport java.net.UnknownHostException;
2847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltimport java.util.ArrayList;
2947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltimport java.util.Collection;
3037e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwaltimport java.util.Collections;
31419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colittiimport java.util.Hashtable;
3247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
3347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt/**
3437e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt * Describes the properties of a network link.
35992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt *
36992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * A link represents a connection to a network.
37992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * It may have multiple addresses and multiple gateways,
38992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * multiple dns servers but only one http proxy.
39992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt *
40992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * Because it's a single network, the dns's
41992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * are interchangeable and don't need associating with
42992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * particular addresses.  The gateways similarly don't
43992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * need associating with particular addresses.
44992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt *
45992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * A dual stack interface works fine in this model:
46992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * each address has it's own prefix length to describe
47992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * the local network.  The dns servers all return
48992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * both v4 addresses and v6 addresses regardless of the
49992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * address family of the server itself (rfc4213) and we
50992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * don't care which is used.  The gateways will be
51992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * selected based on the destination address and the
52992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * source address has no relavence.
53419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti *
54419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti * Links can also be stacked on top of each other.
55419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti * This can be used, for example, to represent a tunnel
56419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti * interface that runs on top of a physical interface.
57419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti *
5847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * @hide
5947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt */
6037e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwaltpublic class LinkProperties implements Parcelable {
61419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    // The interface described by the network link.
624717c261b2c670d5c0925e3527a864aa52db6ac0Robert Greenwalt    private String mIfaceName;
63e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
64e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    private Collection<InetAddress> mDnses = new ArrayList<InetAddress>();
658058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt    private String mDomains;
66e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
6747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    private ProxyProperties mHttpProxy;
6847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
69419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    // Stores the properties of links that are "stacked" above this link.
70419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    // Indexed by interface name to allow modification and to prevent duplicates being added.
71419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    private Hashtable<String, LinkProperties> mStackedLinks =
72419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        new Hashtable<String, LinkProperties>();
73419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti
740a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt    public static class CompareResult<T> {
75ad55d35114237071133eb28ded93a014185d4e35Robert Greenwalt        public Collection<T> removed = new ArrayList<T>();
76ad55d35114237071133eb28ded93a014185d4e35Robert Greenwalt        public Collection<T> added = new ArrayList<T>();
77e822225f7a01ef088ff01f7613f953d5d89945edWink Saville
78e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        @Override
79e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        public String toString() {
800a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt            String retVal = "removed=[";
810a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt            for (T addr : removed) retVal += addr.toString() + ",";
820a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt            retVal += "] added=[";
830a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt            for (T addr : added) retVal += addr.toString() + ",";
84e822225f7a01ef088ff01f7613f953d5d89945edWink Saville            retVal += "]";
85e822225f7a01ef088ff01f7613f953d5d89945edWink Saville            return retVal;
86e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        }
87e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    }
88e822225f7a01ef088ff01f7613f953d5d89945edWink Saville
8937e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    public LinkProperties() {
9047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        clear();
9147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
9247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
9337e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    // copy constructor instead of clone
9437e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    public LinkProperties(LinkProperties source) {
95ef6c1431fa2039a4b8c604d651bb8f4dc0806581Irfan Sheriff        if (source != null) {
96ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff            mIfaceName = source.getInterfaceName();
970d8acea9bb452d1fdbb3d811041f7bdb1b0ef8a3Robert Greenwalt            for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l);
980d8acea9bb452d1fdbb3d811041f7bdb1b0ef8a3Robert Greenwalt            for (InetAddress i : source.getDnses()) mDnses.add(i);
998058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt            mDomains = source.getDomains();
1000d8acea9bb452d1fdbb3d811041f7bdb1b0ef8a3Robert Greenwalt            for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
101be2b058ec1e11e1d33b6d03230c21e5d2d7ac40cWink Saville            mHttpProxy = (source.getHttpProxy() == null)  ?
1028058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt                    null : new ProxyProperties(source.getHttpProxy());
103419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            for (LinkProperties l: source.mStackedLinks.values()) {
104419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti                addStackedLink(l);
105419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            }
106ef6c1431fa2039a4b8c604d651bb8f4dc0806581Irfan Sheriff        }
10737e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    }
10837e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt
109ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    public void setInterfaceName(String iface) {
110ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        mIfaceName = iface;
11145b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti        ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size());
11245b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti        for (RouteInfo route : mRoutes) {
11345b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti            newRoutes.add(routeWithInterface(route));
11445b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti        }
11545b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti        mRoutes = newRoutes;
11647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
117ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
11837e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    public String getInterfaceName() {
119ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        return mIfaceName;
12047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
12147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
1224aa9bcf414282e4bdd10900832baaeaa349bda50Lorenzo Colitti    public Collection<String> getAllInterfaceNames() {
1234aa9bcf414282e4bdd10900832baaeaa349bda50Lorenzo Colitti        Collection interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1);
12455187f18505aad67f824094061af1b6d0a0ebb38Robert Greenwalt        if (mIfaceName != null) interfaceNames.add(new String(mIfaceName));
1254aa9bcf414282e4bdd10900832baaeaa349bda50Lorenzo Colitti        for (LinkProperties stacked: mStackedLinks.values()) {
1264aa9bcf414282e4bdd10900832baaeaa349bda50Lorenzo Colitti            interfaceNames.addAll(stacked.getAllInterfaceNames());
1274aa9bcf414282e4bdd10900832baaeaa349bda50Lorenzo Colitti        }
1284aa9bcf414282e4bdd10900832baaeaa349bda50Lorenzo Colitti        return interfaceNames;
1294aa9bcf414282e4bdd10900832baaeaa349bda50Lorenzo Colitti    }
1304aa9bcf414282e4bdd10900832baaeaa349bda50Lorenzo Colitti
13137e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    public Collection<InetAddress> getAddresses() {
132ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        Collection<InetAddress> addresses = new ArrayList<InetAddress>();
133ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        for (LinkAddress linkAddress : mLinkAddresses) {
134ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff            addresses.add(linkAddress.getAddress());
135ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        }
136ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        return Collections.unmodifiableCollection(addresses);
137ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    }
138ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
139ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    public void addLinkAddress(LinkAddress address) {
14004cac40ff86e175444991c07869cb85219db1019Robert Greenwalt        if (address != null) mLinkAddresses.add(address);
141ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    }
142ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
143ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    public Collection<LinkAddress> getLinkAddresses() {
144ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        return Collections.unmodifiableCollection(mLinkAddresses);
14547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
14647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
14737e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    public void addDns(InetAddress dns) {
14804cac40ff86e175444991c07869cb85219db1019Robert Greenwalt        if (dns != null) mDnses.add(dns);
14947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
150ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
15137e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    public Collection<InetAddress> getDnses() {
15237e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt        return Collections.unmodifiableCollection(mDnses);
15347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
15447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
1558058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt    public String getDomains() {
1568058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt        return mDomains;
1578058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt    }
1588058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt
1598058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt    public void setDomains(String domains) {
1608058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt        mDomains = domains;
1618058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt    }
1628058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt
16345b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti    private RouteInfo routeWithInterface(RouteInfo route) {
16445b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti        return new RouteInfo(
16545b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti            route.getDestination(),
16645b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti            route.getGateway(),
16745b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti            mIfaceName);
16845b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti    }
16945b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti
170aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt    public void addRoute(RouteInfo route) {
17145b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti        if (route != null) {
17245b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti            String routeIface = route.getInterface();
17345b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti            if (routeIface != null && !routeIface.equals(mIfaceName)) {
1741994bc14ab9fd3a3c5dca8851cfc0042bcb25d46Lorenzo Colitti                throw new IllegalArgumentException(
17545b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti                   "Route added with non-matching interface: " + routeIface +
1761994bc14ab9fd3a3c5dca8851cfc0042bcb25d46Lorenzo Colitti                   " vs. " + mIfaceName);
17745b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti            }
17845b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti            mRoutes.add(routeWithInterface(route));
17945b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti        }
18047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
18145b9a5bb93569ca49bbd44f7a518091371687f96Lorenzo Colitti
182419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    /**
183419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * Returns all the routes on this link.
184419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     */
185aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt    public Collection<RouteInfo> getRoutes() {
186aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt        return Collections.unmodifiableCollection(mRoutes);
18747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
18847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
189419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    /**
190419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * Returns all the routes on this link and all the links stacked above it.
191419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     */
192419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    public Collection<RouteInfo> getAllRoutes() {
193419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        Collection<RouteInfo> routes = new ArrayList();
194419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        routes.addAll(mRoutes);
195419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        for (LinkProperties stacked: mStackedLinks.values()) {
196419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            routes.addAll(stacked.getAllRoutes());
197419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        }
1986629bcd6608cccbd5997ac99bf4474c00def0431Robert Greenwalt        return routes;
199419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    }
200419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti
20137e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    public void setHttpProxy(ProxyProperties proxy) {
20247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        mHttpProxy = proxy;
20347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
20437e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    public ProxyProperties getHttpProxy() {
20547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        return mHttpProxy;
20647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
20747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
208419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    /**
209419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * Adds a stacked link.
210419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     *
211419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * If there is already a stacked link with the same interfacename as link,
212419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * that link is replaced with link. Otherwise, link is added to the list
213419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * of stacked links. If link is null, nothing changes.
214419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     *
215419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * @param link The link to add.
216419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     */
217419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    public void addStackedLink(LinkProperties link) {
218419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        if (link != null && link.getInterfaceName() != null) {
219419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            mStackedLinks.put(link.getInterfaceName(), link);
220419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        }
221419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    }
222419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti
223419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    /**
224419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * Removes a stacked link.
225419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     *
226419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * If there a stacked link with the same interfacename as link, it is
227419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * removed. Otherwise, nothing changes.
228419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     *
229419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * @param link The link to add.
230419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     */
231419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    public void removeStackedLink(LinkProperties link) {
232419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        if (link != null && link.getInterfaceName() != null) {
233419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            mStackedLinks.remove(link.getInterfaceName());
234419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        }
235419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    }
236419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti
237419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    /**
238419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * Returns all the links stacked on top of this link.
239419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     */
240419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    public Collection<LinkProperties> getStackedLinks() {
241419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        Collection<LinkProperties> stacked = new ArrayList<LinkProperties>();
242419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        for (LinkProperties link : mStackedLinks.values()) {
243419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti          stacked.add(new LinkProperties(link));
244419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        }
245419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        return Collections.unmodifiableCollection(stacked);
246419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    }
247419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti
24837e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    public void clear() {
249ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        mIfaceName = null;
250e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        mLinkAddresses.clear();
251e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        mDnses.clear();
2528058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt        mDomains = null;
253e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        mRoutes.clear();
25447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        mHttpProxy = null;
255419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        mStackedLinks.clear();
25647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
25747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
25847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    /**
25947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt     * Implement the Parcelable interface
26047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt     * @hide
26147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt     */
26247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    public int describeContents() {
26347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        return 0;
26447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
26547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
2661f6408a96c757b3001c553f8f34ef0bda00a224dWink Saville    @Override
26737e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    public String toString() {
268ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " ");
26947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
270ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        String linkAddresses = "LinkAddresses: [";
2714e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang        for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ",";
272ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        linkAddresses += "] ";
27347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
27447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        String dns = "DnsAddresses: [";
2751f6408a96c757b3001c553f8f34ef0bda00a224dWink Saville        for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ",";
27647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        dns += "] ";
27747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
2788058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt        String domainName = "Domains: " + mDomains;
2798058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt
2808058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt        String routes = " Routes: [";
281aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt        for (RouteInfo route : mRoutes) routes += route.toString() + ",";
282aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt        routes += "] ";
28347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
28447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
285419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        String stacked = "";
286419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        if (mStackedLinks.values().size() > 0) {
287419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            stacked += " Stacked: [";
288419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            for (LinkProperties link: mStackedLinks.values()) {
289419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti                stacked += " [" + link.toString() + " ],";
290419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            }
291419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            stacked += "] ";
292419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        }
29315bc62fe205b755582845829821373985efc60afWink Saville        return "{" + ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked + "}";
294419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    }
295419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti
296419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    /**
297419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * Returns true if this link has an IPv4 address.
298419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     *
299419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
300419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     */
301419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    public boolean hasIPv4Address() {
302419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        for (LinkAddress address : mLinkAddresses) {
303419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti          if (address.getAddress() instanceof Inet4Address) {
304419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            return true;
305419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti          }
306419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        }
307419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        return false;
30847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
30947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
310e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    /**
311e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * Compares this {@code LinkProperties} interface name against the target
312e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     *
313e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * @param target LinkProperties to compare.
314e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * @return {@code true} if both are identical, {@code false} otherwise.
315e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     */
316e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    public boolean isIdenticalInterfaceName(LinkProperties target) {
317e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
318e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    }
319e822225f7a01ef088ff01f7613f953d5d89945edWink Saville
320e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    /**
3214717c261b2c670d5c0925e3527a864aa52db6ac0Robert Greenwalt     * Compares this {@code LinkProperties} interface addresses against the target
322e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     *
323e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * @param target LinkProperties to compare.
324e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * @return {@code true} if both are identical, {@code false} otherwise.
325e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     */
326e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    public boolean isIdenticalAddresses(LinkProperties target) {
327e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        Collection<InetAddress> targetAddresses = target.getAddresses();
328e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        Collection<InetAddress> sourceAddresses = getAddresses();
329e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        return (sourceAddresses.size() == targetAddresses.size()) ?
330e822225f7a01ef088ff01f7613f953d5d89945edWink Saville                    sourceAddresses.containsAll(targetAddresses) : false;
331e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    }
332e822225f7a01ef088ff01f7613f953d5d89945edWink Saville
333e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    /**
334e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * Compares this {@code LinkProperties} DNS addresses against the target
335e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     *
336e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * @param target LinkProperties to compare.
337e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * @return {@code true} if both are identical, {@code false} otherwise.
338e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     */
339e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    public boolean isIdenticalDnses(LinkProperties target) {
340e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        Collection<InetAddress> targetDnses = target.getDnses();
3418058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt        String targetDomains = target.getDomains();
3428058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt        if (mDomains == null) {
3438058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt            if (targetDomains != null) return false;
3448058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt        } else {
3458058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt            if (mDomains.equals(targetDomains) == false) return false;
3468058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt        }
347e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        return (mDnses.size() == targetDnses.size()) ?
348e822225f7a01ef088ff01f7613f953d5d89945edWink Saville                    mDnses.containsAll(targetDnses) : false;
349e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    }
350e822225f7a01ef088ff01f7613f953d5d89945edWink Saville
351e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    /**
352e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * Compares this {@code LinkProperties} Routes against the target
353e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     *
354e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * @param target LinkProperties to compare.
355e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * @return {@code true} if both are identical, {@code false} otherwise.
356e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     */
357e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    public boolean isIdenticalRoutes(LinkProperties target) {
358e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        Collection<RouteInfo> targetRoutes = target.getRoutes();
359e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        return (mRoutes.size() == targetRoutes.size()) ?
360e822225f7a01ef088ff01f7613f953d5d89945edWink Saville                    mRoutes.containsAll(targetRoutes) : false;
361e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    }
362e822225f7a01ef088ff01f7613f953d5d89945edWink Saville
363e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    /**
364e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * Compares this {@code LinkProperties} HttpProxy against the target
365e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     *
366e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * @param target LinkProperties to compare.
367e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * @return {@code true} if both are identical, {@code false} otherwise.
368e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     */
369e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    public boolean isIdenticalHttpProxy(LinkProperties target) {
370e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        return getHttpProxy() == null ? target.getHttpProxy() == null :
371e822225f7a01ef088ff01f7613f953d5d89945edWink Saville                    getHttpProxy().equals(target.getHttpProxy());
372e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    }
3734e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang
374419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    /**
375419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * Compares this {@code LinkProperties} stacked links against the target
376419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     *
377419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * @param target LinkProperties to compare.
378419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * @return {@code true} if both are identical, {@code false} otherwise.
379419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     */
380419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    public boolean isIdenticalStackedLinks(LinkProperties target) {
381419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        if (!mStackedLinks.keys().equals(target.mStackedLinks.keys())) {
382419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            return false;
383419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        }
384419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        for (LinkProperties stacked : mStackedLinks.values()) {
385419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            // Hashtable values can never be null.
386419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            String iface = stacked.getInterfaceName();
387419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            if (!stacked.equals(target.mStackedLinks.get(iface))) {
388419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti                return false;
389419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            }
390419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        }
391419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        return true;
392419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti    }
393419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti
3944e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang    @Override
3954e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang    /**
3964e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     * Compares this {@code LinkProperties} instance against the target
3974e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
3984e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     * all their fields are equal in values.
3994e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     *
4004e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     * For collection fields, such as mDnses, containsAll() is used to check
4014e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     * if two collections contains the same elements, independent of order.
4024e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     * There are two thoughts regarding containsAll()
4034e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
4044e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     * 2. Worst case performance is O(n^2).
4054e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     *
406419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * This method does not check that stacked interfaces are equal, because
407419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * stacked interfaces are not so much a property of the link as a
408419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     * description of connections between links.
409419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti     *
4104e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     * @param obj the object to be tested for equality.
4114e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     * @return {@code true} if both objects are equal, {@code false} otherwise.
4124e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     */
4134e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang    public boolean equals(Object obj) {
4144e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang        if (this == obj) return true;
4154e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang
4164e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang        if (!(obj instanceof LinkProperties)) return false;
4174e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang
4184e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang        LinkProperties target = (LinkProperties) obj;
4194e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang
420e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        return isIdenticalInterfaceName(target) &&
421e822225f7a01ef088ff01f7613f953d5d89945edWink Saville                isIdenticalAddresses(target) &&
422e822225f7a01ef088ff01f7613f953d5d89945edWink Saville                isIdenticalDnses(target) &&
423e822225f7a01ef088ff01f7613f953d5d89945edWink Saville                isIdenticalRoutes(target) &&
424419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti                isIdenticalHttpProxy(target) &&
425419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti                isIdenticalStackedLinks(target);
426e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    }
4274e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang
428e822225f7a01ef088ff01f7613f953d5d89945edWink Saville    /**
429e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * Return two lists, a list of addresses that would be removed from
430e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * mLinkAddresses and a list of addresses that would be added to
431e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * mLinkAddress which would then result in target and mLinkAddresses
432e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * being the same list.
433e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     *
4340a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     * @param target is a LinkProperties with the new list of addresses
435e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     * @return the removed and added lists.
436e822225f7a01ef088ff01f7613f953d5d89945edWink Saville     */
4370a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt    public CompareResult<LinkAddress> compareAddresses(LinkProperties target) {
438e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        /*
439e822225f7a01ef088ff01f7613f953d5d89945edWink Saville         * Duplicate the LinkAddresses into removed, we will be removing
440e822225f7a01ef088ff01f7613f953d5d89945edWink Saville         * address which are common between mLinkAddresses and target
441e822225f7a01ef088ff01f7613f953d5d89945edWink Saville         * leaving the addresses that are different. And address which
442e822225f7a01ef088ff01f7613f953d5d89945edWink Saville         * are in target but not in mLinkAddresses are placed in the
443e822225f7a01ef088ff01f7613f953d5d89945edWink Saville         * addedAddresses.
444e822225f7a01ef088ff01f7613f953d5d89945edWink Saville         */
4450a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        CompareResult<LinkAddress> result = new CompareResult<LinkAddress>();
446e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        result.removed = new ArrayList<LinkAddress>(mLinkAddresses);
447e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        result.added.clear();
4480a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        if (target != null) {
4490a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt            for (LinkAddress newAddress : target.getLinkAddresses()) {
4500a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt                if (! result.removed.remove(newAddress)) {
4510a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt                    result.added.add(newAddress);
4520a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt                }
453e822225f7a01ef088ff01f7613f953d5d89945edWink Saville            }
454e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        }
455e822225f7a01ef088ff01f7613f953d5d89945edWink Saville        return result;
4564e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang    }
4574e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang
4580a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt    /**
4590a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     * Return two lists, a list of dns addresses that would be removed from
4600a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     * mDnses and a list of addresses that would be added to
4610a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     * mDnses which would then result in target and mDnses
4620a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     * being the same list.
4630a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     *
4640a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     * @param target is a LinkProperties with the new list of dns addresses
4650a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     * @return the removed and added lists.
4660a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     */
4670a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt    public CompareResult<InetAddress> compareDnses(LinkProperties target) {
4680a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        /*
4690a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt         * Duplicate the InetAddresses into removed, we will be removing
4700a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt         * dns address which are common between mDnses and target
4710a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt         * leaving the addresses that are different. And dns address which
4720a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt         * are in target but not in mDnses are placed in the
4730a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt         * addedAddresses.
4740a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt         */
4750a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        CompareResult<InetAddress> result = new CompareResult<InetAddress>();
4760a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt
4770a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        result.removed = new ArrayList<InetAddress>(mDnses);
4780a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        result.added.clear();
4790a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        if (target != null) {
4800a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt            for (InetAddress newAddress : target.getDnses()) {
4810a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt                if (! result.removed.remove(newAddress)) {
4820a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt                    result.added.add(newAddress);
4830a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt                }
4840a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt            }
4850a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        }
4860a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        return result;
4870a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt    }
4880a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt
4890a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt    /**
4900a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     * Return two lists, a list of routes that would be removed from
4910a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     * mRoutes and a list of routes that would be added to
4920a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     * mRoutes which would then result in target and mRoutes
4930a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     * being the same list.
4940a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     *
4950a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     * @param target is a LinkProperties with the new list of routes
4960a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     * @return the removed and added lists.
4970a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt     */
4980a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt    public CompareResult<RouteInfo> compareRoutes(LinkProperties target) {
4990a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        /*
5000a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt         * Duplicate the RouteInfos into removed, we will be removing
5011994bc14ab9fd3a3c5dca8851cfc0042bcb25d46Lorenzo Colitti         * routes which are common between mRoutes and target
5020a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt         * leaving the routes that are different. And route address which
5030a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt         * are in target but not in mRoutes are placed in added.
5040a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt         */
5050a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        CompareResult<RouteInfo> result = new CompareResult<RouteInfo>();
5060a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt
507419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        result.removed = getAllRoutes();
5080a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        result.added.clear();
5090a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        if (target != null) {
510419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti            for (RouteInfo r : target.getAllRoutes()) {
5110a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt                if (! result.removed.remove(r)) {
5120a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt                    result.added.add(r);
5130a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt                }
5140a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt            }
5150a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        }
5160a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt        return result;
5170a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt    }
5180a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt
5190a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt
5204e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang    @Override
5214e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang    /**
5224e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     * generate hashcode based on significant fields
5234e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     * Equal objects must produce the same hash code, while unequal objects
5244e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     * may have the same hash codes.
5254e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang     */
5264e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang    public int hashCode() {
5274e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang        return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
5284e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang                + mLinkAddresses.size() * 31
5294e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang                + mDnses.size() * 37
5308058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt                + ((null == mDomains) ? 0 : mDomains.hashCode())
531aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt                + mRoutes.size() * 41
532419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti                + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
533419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti                + mStackedLinks.hashCode() * 47);
5344e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang    }
5354e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang
53647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    /**
53747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt     * Implement the Parcelable interface.
53847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt     */
53937e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    public void writeToParcel(Parcel dest, int flags) {
54047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        dest.writeString(getInterfaceName());
541ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        dest.writeInt(mLinkAddresses.size());
542ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        for(LinkAddress linkAddress : mLinkAddresses) {
543ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff            dest.writeParcelable(linkAddress, flags);
54447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        }
545ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
54647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        dest.writeInt(mDnses.size());
54747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        for(InetAddress d : mDnses) {
54847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt            dest.writeByteArray(d.getAddress());
54947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        }
5508058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt        dest.writeString(mDomains);
551992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt
552aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt        dest.writeInt(mRoutes.size());
553aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt        for(RouteInfo route : mRoutes) {
554aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt            dest.writeParcelable(route, flags);
55547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        }
556992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt
55747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        if (mHttpProxy != null) {
55847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt            dest.writeByte((byte)1);
55947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt            dest.writeParcelable(mHttpProxy, flags);
56047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        } else {
56147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt            dest.writeByte((byte)0);
56247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        }
563419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        ArrayList<LinkProperties> stackedLinks = new ArrayList(mStackedLinks.values());
564419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti        dest.writeList(stackedLinks);
56547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    }
56647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
56747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt    /**
56847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt     * Implement the Parcelable interface.
56947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt     */
57037e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt    public static final Creator<LinkProperties> CREATOR =
57137e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt        new Creator<LinkProperties>() {
57237e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt            public LinkProperties createFromParcel(Parcel in) {
57337e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt                LinkProperties netProp = new LinkProperties();
5744717c261b2c670d5c0925e3527a864aa52db6ac0Robert Greenwalt
57547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                String iface = in.readString();
57647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                if (iface != null) {
5774717c261b2c670d5c0925e3527a864aa52db6ac0Robert Greenwalt                    netProp.setInterfaceName(iface);
57847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                }
57947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                int addressCount = in.readInt();
58047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                for (int i=0; i<addressCount; i++) {
581ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff                    netProp.addLinkAddress((LinkAddress)in.readParcelable(null));
58247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                }
58347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                addressCount = in.readInt();
58447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                for (int i=0; i<addressCount; i++) {
58547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                    try {
5861cf56ab9c68334d9124c52bcede06aaa0b17c730Irfan Sheriff                        netProp.addDns(InetAddress.getByAddress(in.createByteArray()));
58747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                    } catch (UnknownHostException e) { }
58847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                }
5898058f621891b41c6864b6004c1c47647436a0ac1Robert Greenwalt                netProp.setDomains(in.readString());
590992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt                addressCount = in.readInt();
591992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt                for (int i=0; i<addressCount; i++) {
592aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt                    netProp.addRoute((RouteInfo)in.readParcelable(null));
59347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                }
59447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                if (in.readByte() == 1) {
59547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                    netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
59647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                }
597419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti                ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
598419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti                in.readList(stackedLinks, LinkProperties.class.getClassLoader());
599419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti                for (LinkProperties stackedLink: stackedLinks) {
600419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti                    netProp.addStackedLink(stackedLink);
601419a4ce9e461177d75eca5fd71fc8c275969e479Lorenzo Colitti                }
60247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt                return netProp;
60347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt            }
60447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt
60537e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt            public LinkProperties[] newArray(int size) {
60637e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt                return new LinkProperties[size];
60747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt            }
60847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt        };
60947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt}
610