blob: 1f73c4ad717f74bc81c2a652b6b7fd9d1617ffb8 [file] [log] [blame]
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001/*
Wink Saville6e809972010-09-21 09:15:35 -07002 * Copyright (C) 2010 The Android Open Source Project
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net;
18
Robert Greenwalt37e65eb2010-08-30 10:56:47 -070019import android.net.ProxyProperties;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070020import android.os.Parcelable;
21import android.os.Parcel;
John Wang4e900092011-04-04 12:35:42 -070022import android.text.TextUtils;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070023
24import java.net.InetAddress;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -080025import java.net.Inet4Address;
Lorenzo Colitti4faa0272013-08-08 11:00:12 +090026import java.net.Inet6Address;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -080027
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070028import java.net.UnknownHostException;
29import java.util.ArrayList;
30import java.util.Collection;
Robert Greenwalt37e65eb2010-08-30 10:56:47 -070031import java.util.Collections;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -080032import java.util.Hashtable;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070033
34/**
Robert Greenwalt37e65eb2010-08-30 10:56:47 -070035 * Describes the properties of a network link.
Robert Greenwalt992564e2011-02-09 13:56:06 -080036 *
37 * A link represents a connection to a network.
38 * It may have multiple addresses and multiple gateways,
39 * multiple dns servers but only one http proxy.
40 *
41 * Because it's a single network, the dns's
42 * are interchangeable and don't need associating with
43 * particular addresses. The gateways similarly don't
44 * need associating with particular addresses.
45 *
46 * A dual stack interface works fine in this model:
47 * each address has it's own prefix length to describe
48 * the local network. The dns servers all return
49 * both v4 addresses and v6 addresses regardless of the
50 * address family of the server itself (rfc4213) and we
51 * don't care which is used. The gateways will be
52 * selected based on the destination address and the
53 * source address has no relavence.
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -080054 *
55 * Links can also be stacked on top of each other.
56 * This can be used, for example, to represent a tunnel
57 * interface that runs on top of a physical interface.
58 *
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070059 * @hide
60 */
Robert Greenwalt37e65eb2010-08-30 10:56:47 -070061public class LinkProperties implements Parcelable {
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -080062 // The interface described by the network link.
Robert Greenwalt4717c262012-10-31 14:32:53 -070063 private String mIfaceName;
Wink Savillee8222252011-07-13 13:44:13 -070064 private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
65 private Collection<InetAddress> mDnses = new ArrayList<InetAddress>();
Robert Greenwalt8058f622012-11-09 10:52:27 -080066 private String mDomains;
Wink Savillee8222252011-07-13 13:44:13 -070067 private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070068 private ProxyProperties mHttpProxy;
69
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -080070 // Stores the properties of links that are "stacked" above this link.
71 // Indexed by interface name to allow modification and to prevent duplicates being added.
72 private Hashtable<String, LinkProperties> mStackedLinks =
73 new Hashtable<String, LinkProperties>();
74
Robert Greenwalt0a46db52011-07-14 14:28:05 -070075 public static class CompareResult<T> {
Robert Greenwaltad55d352011-07-22 11:55:33 -070076 public Collection<T> removed = new ArrayList<T>();
77 public Collection<T> added = new ArrayList<T>();
Wink Savillee8222252011-07-13 13:44:13 -070078
79 @Override
80 public String toString() {
Robert Greenwalt0a46db52011-07-14 14:28:05 -070081 String retVal = "removed=[";
82 for (T addr : removed) retVal += addr.toString() + ",";
83 retVal += "] added=[";
84 for (T addr : added) retVal += addr.toString() + ",";
Wink Savillee8222252011-07-13 13:44:13 -070085 retVal += "]";
86 return retVal;
87 }
88 }
89
Robert Greenwalt37e65eb2010-08-30 10:56:47 -070090 public LinkProperties() {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070091 clear();
92 }
93
Robert Greenwalt37e65eb2010-08-30 10:56:47 -070094 // copy constructor instead of clone
95 public LinkProperties(LinkProperties source) {
Irfan Sheriffef6c1432010-08-30 20:37:17 -070096 if (source != null) {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -070097 mIfaceName = source.getInterfaceName();
Robert Greenwalt0d8acea2011-07-28 17:21:25 -070098 for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l);
99 for (InetAddress i : source.getDnses()) mDnses.add(i);
Robert Greenwalt8058f622012-11-09 10:52:27 -0800100 mDomains = source.getDomains();
Robert Greenwalt0d8acea2011-07-28 17:21:25 -0700101 for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
Wink Savillebe2b0582011-05-18 15:59:04 -0700102 mHttpProxy = (source.getHttpProxy() == null) ?
Robert Greenwalt8058f622012-11-09 10:52:27 -0800103 null : new ProxyProperties(source.getHttpProxy());
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800104 for (LinkProperties l: source.mStackedLinks.values()) {
105 addStackedLink(l);
106 }
Irfan Sheriffef6c1432010-08-30 20:37:17 -0700107 }
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700108 }
109
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700110 public void setInterfaceName(String iface) {
111 mIfaceName = iface;
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800112 ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size());
113 for (RouteInfo route : mRoutes) {
114 newRoutes.add(routeWithInterface(route));
115 }
116 mRoutes = newRoutes;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700117 }
118
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700119 public String getInterfaceName() {
120 return mIfaceName;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700121 }
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700122
Lorenzo Colitti4aa9bcf2013-03-20 19:22:58 +0900123 public Collection<String> getAllInterfaceNames() {
124 Collection interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1);
Robert Greenwalt55187f12013-03-22 12:00:17 -0700125 if (mIfaceName != null) interfaceNames.add(new String(mIfaceName));
Lorenzo Colitti4aa9bcf2013-03-20 19:22:58 +0900126 for (LinkProperties stacked: mStackedLinks.values()) {
127 interfaceNames.addAll(stacked.getAllInterfaceNames());
128 }
129 return interfaceNames;
130 }
131
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900132 /**
133 * Returns all the addresses on this link.
134 */
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700135 public Collection<InetAddress> getAddresses() {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700136 Collection<InetAddress> addresses = new ArrayList<InetAddress>();
137 for (LinkAddress linkAddress : mLinkAddresses) {
138 addresses.add(linkAddress.getAddress());
139 }
140 return Collections.unmodifiableCollection(addresses);
141 }
142
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900143 /**
144 * Returns all the addresses on this link and all the links stacked above it.
145 */
146 public Collection<InetAddress> getAllAddresses() {
147 Collection<InetAddress> addresses = new ArrayList<InetAddress>();
148 for (LinkAddress linkAddress : mLinkAddresses) {
149 addresses.add(linkAddress.getAddress());
150 }
151 for (LinkProperties stacked: mStackedLinks.values()) {
152 addresses.addAll(stacked.getAllAddresses());
153 }
154 return addresses;
155 }
156
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900157 /**
158 * Adds a link address if it does not exist, or update it if it does.
159 * @param address The {@code LinkAddress} to add.
160 * @return true if the address was added, false if it already existed.
161 */
162 public boolean addLinkAddress(LinkAddress address) {
163 // TODO: when the LinkAddress has other attributes beyond the
164 // address and the prefix length, update them here.
165 if (address != null && !mLinkAddresses.contains(address)) {
166 mLinkAddresses.add(address);
167 return true;
168 }
169 return false;
170 }
171
172 /**
173 * Removes a link address.
174 * @param address The {@code LinkAddress} to remove.
175 * @return true if the address was removed, false if it did not exist.
176 */
177 public boolean removeLinkAddress(LinkAddress toRemove) {
178 return mLinkAddresses.remove(toRemove);
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700179 }
180
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900181 /**
182 * Returns all the addresses on this link.
183 */
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700184 public Collection<LinkAddress> getLinkAddresses() {
185 return Collections.unmodifiableCollection(mLinkAddresses);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700186 }
187
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900188 /**
189 * Returns all the addresses on this link and all the links stacked above it.
190 */
191 public Collection<LinkAddress> getAllLinkAddresses() {
192 Collection<LinkAddress> addresses = new ArrayList<LinkAddress>();
193 addresses.addAll(mLinkAddresses);
194 for (LinkProperties stacked: mStackedLinks.values()) {
195 addresses.addAll(stacked.getAllLinkAddresses());
196 }
197 return addresses;
198 }
199
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700200 public void addDns(InetAddress dns) {
Robert Greenwalt04cac402011-03-02 17:03:37 -0800201 if (dns != null) mDnses.add(dns);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700202 }
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700203
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700204 public Collection<InetAddress> getDnses() {
205 return Collections.unmodifiableCollection(mDnses);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700206 }
207
Robert Greenwalt8058f622012-11-09 10:52:27 -0800208 public String getDomains() {
209 return mDomains;
210 }
211
212 public void setDomains(String domains) {
213 mDomains = domains;
214 }
215
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800216 private RouteInfo routeWithInterface(RouteInfo route) {
217 return new RouteInfo(
218 route.getDestination(),
219 route.getGateway(),
220 mIfaceName);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700221 }
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800222
223 public void addRoute(RouteInfo route) {
224 if (route != null) {
225 String routeIface = route.getInterface();
226 if (routeIface != null && !routeIface.equals(mIfaceName)) {
Lorenzo Colitti1994bc12013-03-08 19:11:40 -0800227 throw new IllegalArgumentException(
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800228 "Route added with non-matching interface: " + routeIface +
Lorenzo Colitti1994bc12013-03-08 19:11:40 -0800229 " vs. " + mIfaceName);
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800230 }
231 mRoutes.add(routeWithInterface(route));
232 }
233 }
234
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800235 /**
236 * Returns all the routes on this link.
237 */
Robert Greenwaltaa70f102011-04-28 14:28:50 -0700238 public Collection<RouteInfo> getRoutes() {
239 return Collections.unmodifiableCollection(mRoutes);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700240 }
241
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800242 /**
243 * Returns all the routes on this link and all the links stacked above it.
244 */
245 public Collection<RouteInfo> getAllRoutes() {
246 Collection<RouteInfo> routes = new ArrayList();
247 routes.addAll(mRoutes);
248 for (LinkProperties stacked: mStackedLinks.values()) {
249 routes.addAll(stacked.getAllRoutes());
250 }
Robert Greenwalt6629bcd2013-03-15 11:28:50 -0700251 return routes;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800252 }
253
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700254 public void setHttpProxy(ProxyProperties proxy) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700255 mHttpProxy = proxy;
256 }
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700257 public ProxyProperties getHttpProxy() {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700258 return mHttpProxy;
259 }
260
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800261 /**
262 * Adds a stacked link.
263 *
264 * If there is already a stacked link with the same interfacename as link,
265 * that link is replaced with link. Otherwise, link is added to the list
266 * of stacked links. If link is null, nothing changes.
267 *
268 * @param link The link to add.
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900269 * @return true if the link was stacked, false otherwise.
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800270 */
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900271 public boolean addStackedLink(LinkProperties link) {
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800272 if (link != null && link.getInterfaceName() != null) {
273 mStackedLinks.put(link.getInterfaceName(), link);
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900274 return true;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800275 }
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900276 return false;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800277 }
278
279 /**
280 * Removes a stacked link.
281 *
282 * If there a stacked link with the same interfacename as link, it is
283 * removed. Otherwise, nothing changes.
284 *
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900285 * @param link The link to remove.
286 * @return true if the link was removed, false otherwise.
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800287 */
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900288 public boolean removeStackedLink(LinkProperties link) {
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800289 if (link != null && link.getInterfaceName() != null) {
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900290 LinkProperties removed = mStackedLinks.remove(link.getInterfaceName());
291 return removed != null;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800292 }
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900293 return false;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800294 }
295
296 /**
297 * Returns all the links stacked on top of this link.
298 */
299 public Collection<LinkProperties> getStackedLinks() {
300 Collection<LinkProperties> stacked = new ArrayList<LinkProperties>();
301 for (LinkProperties link : mStackedLinks.values()) {
302 stacked.add(new LinkProperties(link));
303 }
304 return Collections.unmodifiableCollection(stacked);
305 }
306
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700307 public void clear() {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700308 mIfaceName = null;
Wink Savillee8222252011-07-13 13:44:13 -0700309 mLinkAddresses.clear();
310 mDnses.clear();
Robert Greenwalt8058f622012-11-09 10:52:27 -0800311 mDomains = null;
Wink Savillee8222252011-07-13 13:44:13 -0700312 mRoutes.clear();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700313 mHttpProxy = null;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800314 mStackedLinks.clear();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700315 }
316
317 /**
318 * Implement the Parcelable interface
319 * @hide
320 */
321 public int describeContents() {
322 return 0;
323 }
324
Wink Saville1f6408a2010-08-27 11:15:18 -0700325 @Override
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700326 public String toString() {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700327 String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " ");
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700328
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700329 String linkAddresses = "LinkAddresses: [";
John Wang4e900092011-04-04 12:35:42 -0700330 for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ",";
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700331 linkAddresses += "] ";
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700332
333 String dns = "DnsAddresses: [";
Wink Saville1f6408a2010-08-27 11:15:18 -0700334 for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ",";
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700335 dns += "] ";
336
Robert Greenwalt8058f622012-11-09 10:52:27 -0800337 String domainName = "Domains: " + mDomains;
338
339 String routes = " Routes: [";
Robert Greenwaltaa70f102011-04-28 14:28:50 -0700340 for (RouteInfo route : mRoutes) routes += route.toString() + ",";
341 routes += "] ";
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700342 String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700343
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800344 String stacked = "";
345 if (mStackedLinks.values().size() > 0) {
346 stacked += " Stacked: [";
347 for (LinkProperties link: mStackedLinks.values()) {
348 stacked += " [" + link.toString() + " ],";
349 }
350 stacked += "] ";
351 }
Wink Saville15bc62f2013-03-27 16:21:43 -0700352 return "{" + ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked + "}";
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800353 }
354
355 /**
356 * Returns true if this link has an IPv4 address.
357 *
358 * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
359 */
360 public boolean hasIPv4Address() {
361 for (LinkAddress address : mLinkAddresses) {
362 if (address.getAddress() instanceof Inet4Address) {
363 return true;
364 }
365 }
366 return false;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700367 }
368
Wink Savillee8222252011-07-13 13:44:13 -0700369 /**
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900370 * Returns true if this link has an IPv6 address.
371 *
372 * @return {@code true} if there is an IPv6 address, {@code false} otherwise.
373 */
374 public boolean hasIPv6Address() {
375 for (LinkAddress address : mLinkAddresses) {
376 if (address.getAddress() instanceof Inet6Address) {
377 return true;
378 }
379 }
380 return false;
381 }
382
383 /**
Wink Savillee8222252011-07-13 13:44:13 -0700384 * Compares this {@code LinkProperties} interface name against the target
385 *
386 * @param target LinkProperties to compare.
387 * @return {@code true} if both are identical, {@code false} otherwise.
388 */
389 public boolean isIdenticalInterfaceName(LinkProperties target) {
390 return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
391 }
392
393 /**
Robert Greenwalt4717c262012-10-31 14:32:53 -0700394 * Compares this {@code LinkProperties} interface addresses against the target
Wink Savillee8222252011-07-13 13:44:13 -0700395 *
396 * @param target LinkProperties to compare.
397 * @return {@code true} if both are identical, {@code false} otherwise.
398 */
399 public boolean isIdenticalAddresses(LinkProperties target) {
400 Collection<InetAddress> targetAddresses = target.getAddresses();
401 Collection<InetAddress> sourceAddresses = getAddresses();
402 return (sourceAddresses.size() == targetAddresses.size()) ?
403 sourceAddresses.containsAll(targetAddresses) : false;
404 }
405
406 /**
407 * Compares this {@code LinkProperties} DNS addresses against the target
408 *
409 * @param target LinkProperties to compare.
410 * @return {@code true} if both are identical, {@code false} otherwise.
411 */
412 public boolean isIdenticalDnses(LinkProperties target) {
413 Collection<InetAddress> targetDnses = target.getDnses();
Robert Greenwalt8058f622012-11-09 10:52:27 -0800414 String targetDomains = target.getDomains();
415 if (mDomains == null) {
416 if (targetDomains != null) return false;
417 } else {
418 if (mDomains.equals(targetDomains) == false) return false;
419 }
Wink Savillee8222252011-07-13 13:44:13 -0700420 return (mDnses.size() == targetDnses.size()) ?
421 mDnses.containsAll(targetDnses) : false;
422 }
423
424 /**
425 * Compares this {@code LinkProperties} Routes against the target
426 *
427 * @param target LinkProperties to compare.
428 * @return {@code true} if both are identical, {@code false} otherwise.
429 */
430 public boolean isIdenticalRoutes(LinkProperties target) {
431 Collection<RouteInfo> targetRoutes = target.getRoutes();
432 return (mRoutes.size() == targetRoutes.size()) ?
433 mRoutes.containsAll(targetRoutes) : false;
434 }
435
436 /**
437 * Compares this {@code LinkProperties} HttpProxy against the target
438 *
439 * @param target LinkProperties to compare.
440 * @return {@code true} if both are identical, {@code false} otherwise.
441 */
442 public boolean isIdenticalHttpProxy(LinkProperties target) {
443 return getHttpProxy() == null ? target.getHttpProxy() == null :
444 getHttpProxy().equals(target.getHttpProxy());
445 }
John Wang4e900092011-04-04 12:35:42 -0700446
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800447 /**
448 * Compares this {@code LinkProperties} stacked links against the target
449 *
450 * @param target LinkProperties to compare.
451 * @return {@code true} if both are identical, {@code false} otherwise.
452 */
453 public boolean isIdenticalStackedLinks(LinkProperties target) {
Lorenzo Colitti213f98b2013-04-01 10:47:43 +0900454 if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800455 return false;
456 }
457 for (LinkProperties stacked : mStackedLinks.values()) {
458 // Hashtable values can never be null.
459 String iface = stacked.getInterfaceName();
460 if (!stacked.equals(target.mStackedLinks.get(iface))) {
461 return false;
462 }
463 }
464 return true;
465 }
466
John Wang4e900092011-04-04 12:35:42 -0700467 @Override
468 /**
469 * Compares this {@code LinkProperties} instance against the target
470 * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
471 * all their fields are equal in values.
472 *
473 * For collection fields, such as mDnses, containsAll() is used to check
474 * if two collections contains the same elements, independent of order.
475 * There are two thoughts regarding containsAll()
476 * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
477 * 2. Worst case performance is O(n^2).
478 *
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800479 * This method does not check that stacked interfaces are equal, because
480 * stacked interfaces are not so much a property of the link as a
481 * description of connections between links.
482 *
John Wang4e900092011-04-04 12:35:42 -0700483 * @param obj the object to be tested for equality.
484 * @return {@code true} if both objects are equal, {@code false} otherwise.
485 */
486 public boolean equals(Object obj) {
487 if (this == obj) return true;
488
489 if (!(obj instanceof LinkProperties)) return false;
490
John Wang4e900092011-04-04 12:35:42 -0700491 LinkProperties target = (LinkProperties) obj;
492
Wink Savillee8222252011-07-13 13:44:13 -0700493 return isIdenticalInterfaceName(target) &&
494 isIdenticalAddresses(target) &&
495 isIdenticalDnses(target) &&
496 isIdenticalRoutes(target) &&
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800497 isIdenticalHttpProxy(target) &&
498 isIdenticalStackedLinks(target);
Wink Savillee8222252011-07-13 13:44:13 -0700499 }
John Wang4e900092011-04-04 12:35:42 -0700500
Wink Savillee8222252011-07-13 13:44:13 -0700501 /**
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900502 * Compares the addresses in this LinkProperties with another
503 * LinkProperties, examining only addresses on the base link.
Wink Savillee8222252011-07-13 13:44:13 -0700504 *
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900505 * @param target a LinkProperties with the new list of addresses
506 * @return the differences between the addresses.
Wink Savillee8222252011-07-13 13:44:13 -0700507 */
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700508 public CompareResult<LinkAddress> compareAddresses(LinkProperties target) {
Wink Savillee8222252011-07-13 13:44:13 -0700509 /*
510 * Duplicate the LinkAddresses into removed, we will be removing
511 * address which are common between mLinkAddresses and target
512 * leaving the addresses that are different. And address which
513 * are in target but not in mLinkAddresses are placed in the
514 * addedAddresses.
515 */
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700516 CompareResult<LinkAddress> result = new CompareResult<LinkAddress>();
Wink Savillee8222252011-07-13 13:44:13 -0700517 result.removed = new ArrayList<LinkAddress>(mLinkAddresses);
518 result.added.clear();
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700519 if (target != null) {
520 for (LinkAddress newAddress : target.getLinkAddresses()) {
521 if (! result.removed.remove(newAddress)) {
522 result.added.add(newAddress);
523 }
Wink Savillee8222252011-07-13 13:44:13 -0700524 }
525 }
526 return result;
John Wang4e900092011-04-04 12:35:42 -0700527 }
528
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700529 /**
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900530 * Compares the DNS addresses in this LinkProperties with another
531 * LinkProperties, examining only DNS addresses on the base link.
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700532 *
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900533 * @param target a LinkProperties with the new list of dns addresses
534 * @return the differences between the DNS addresses.
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700535 */
536 public CompareResult<InetAddress> compareDnses(LinkProperties target) {
537 /*
538 * Duplicate the InetAddresses into removed, we will be removing
539 * dns address which are common between mDnses and target
540 * leaving the addresses that are different. And dns address which
541 * are in target but not in mDnses are placed in the
542 * addedAddresses.
543 */
544 CompareResult<InetAddress> result = new CompareResult<InetAddress>();
545
546 result.removed = new ArrayList<InetAddress>(mDnses);
547 result.added.clear();
548 if (target != null) {
549 for (InetAddress newAddress : target.getDnses()) {
550 if (! result.removed.remove(newAddress)) {
551 result.added.add(newAddress);
552 }
553 }
554 }
555 return result;
556 }
557
558 /**
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900559 * Compares all routes in this LinkProperties with another LinkProperties,
560 * examining both the the base link and all stacked links.
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700561 *
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900562 * @param target a LinkProperties with the new list of routes
563 * @return the differences between the routes.
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700564 */
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900565 public CompareResult<RouteInfo> compareAllRoutes(LinkProperties target) {
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700566 /*
567 * Duplicate the RouteInfos into removed, we will be removing
Lorenzo Colitti1994bc12013-03-08 19:11:40 -0800568 * routes which are common between mRoutes and target
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700569 * leaving the routes that are different. And route address which
570 * are in target but not in mRoutes are placed in added.
571 */
572 CompareResult<RouteInfo> result = new CompareResult<RouteInfo>();
573
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800574 result.removed = getAllRoutes();
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700575 result.added.clear();
576 if (target != null) {
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800577 for (RouteInfo r : target.getAllRoutes()) {
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700578 if (! result.removed.remove(r)) {
579 result.added.add(r);
580 }
581 }
582 }
583 return result;
584 }
585
586
John Wang4e900092011-04-04 12:35:42 -0700587 @Override
588 /**
589 * generate hashcode based on significant fields
590 * Equal objects must produce the same hash code, while unequal objects
591 * may have the same hash codes.
592 */
593 public int hashCode() {
594 return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
595 + mLinkAddresses.size() * 31
596 + mDnses.size() * 37
Robert Greenwalt8058f622012-11-09 10:52:27 -0800597 + ((null == mDomains) ? 0 : mDomains.hashCode())
Robert Greenwaltaa70f102011-04-28 14:28:50 -0700598 + mRoutes.size() * 41
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800599 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
600 + mStackedLinks.hashCode() * 47);
John Wang4e900092011-04-04 12:35:42 -0700601 }
602
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700603 /**
604 * Implement the Parcelable interface.
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700605 */
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700606 public void writeToParcel(Parcel dest, int flags) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700607 dest.writeString(getInterfaceName());
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700608 dest.writeInt(mLinkAddresses.size());
609 for(LinkAddress linkAddress : mLinkAddresses) {
610 dest.writeParcelable(linkAddress, flags);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700611 }
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700612
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700613 dest.writeInt(mDnses.size());
614 for(InetAddress d : mDnses) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700615 dest.writeByteArray(d.getAddress());
616 }
Robert Greenwalt8058f622012-11-09 10:52:27 -0800617 dest.writeString(mDomains);
Robert Greenwalt992564e2011-02-09 13:56:06 -0800618
Robert Greenwaltaa70f102011-04-28 14:28:50 -0700619 dest.writeInt(mRoutes.size());
620 for(RouteInfo route : mRoutes) {
621 dest.writeParcelable(route, flags);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700622 }
Robert Greenwalt992564e2011-02-09 13:56:06 -0800623
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700624 if (mHttpProxy != null) {
625 dest.writeByte((byte)1);
626 dest.writeParcelable(mHttpProxy, flags);
627 } else {
628 dest.writeByte((byte)0);
629 }
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800630 ArrayList<LinkProperties> stackedLinks = new ArrayList(mStackedLinks.values());
631 dest.writeList(stackedLinks);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700632 }
633
634 /**
635 * Implement the Parcelable interface.
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700636 */
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700637 public static final Creator<LinkProperties> CREATOR =
638 new Creator<LinkProperties>() {
639 public LinkProperties createFromParcel(Parcel in) {
640 LinkProperties netProp = new LinkProperties();
Robert Greenwalt4717c262012-10-31 14:32:53 -0700641
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700642 String iface = in.readString();
643 if (iface != null) {
Robert Greenwalt4717c262012-10-31 14:32:53 -0700644 netProp.setInterfaceName(iface);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700645 }
646 int addressCount = in.readInt();
647 for (int i=0; i<addressCount; i++) {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700648 netProp.addLinkAddress((LinkAddress)in.readParcelable(null));
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700649 }
650 addressCount = in.readInt();
651 for (int i=0; i<addressCount; i++) {
652 try {
Irfan Sheriff1cf56ab2010-08-04 15:15:49 -0700653 netProp.addDns(InetAddress.getByAddress(in.createByteArray()));
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700654 } catch (UnknownHostException e) { }
655 }
Robert Greenwalt8058f622012-11-09 10:52:27 -0800656 netProp.setDomains(in.readString());
Robert Greenwalt992564e2011-02-09 13:56:06 -0800657 addressCount = in.readInt();
658 for (int i=0; i<addressCount; i++) {
Robert Greenwaltaa70f102011-04-28 14:28:50 -0700659 netProp.addRoute((RouteInfo)in.readParcelable(null));
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700660 }
661 if (in.readByte() == 1) {
662 netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
663 }
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800664 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
665 in.readList(stackedLinks, LinkProperties.class.getClassLoader());
666 for (LinkProperties stackedLink: stackedLinks) {
667 netProp.addStackedLink(stackedLink);
668 }
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700669 return netProp;
670 }
671
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700672 public LinkProperties[] newArray(int size) {
673 return new LinkProperties[size];
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700674 }
675 };
676}