blob: b4d07a1ec23c954cbe211a8d51900adb024473bd [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;
sy.yun9d9b74a2013-09-02 05:24:09 +090069 private int mMtu;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070070
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -080071 // Stores the properties of links that are "stacked" above this link.
72 // Indexed by interface name to allow modification and to prevent duplicates being added.
73 private Hashtable<String, LinkProperties> mStackedLinks =
74 new Hashtable<String, LinkProperties>();
75
Robert Greenwalt0a46db52011-07-14 14:28:05 -070076 public static class CompareResult<T> {
Robert Greenwaltad55d352011-07-22 11:55:33 -070077 public Collection<T> removed = new ArrayList<T>();
78 public Collection<T> added = new ArrayList<T>();
Wink Savillee8222252011-07-13 13:44:13 -070079
80 @Override
81 public String toString() {
Robert Greenwalt0a46db52011-07-14 14:28:05 -070082 String retVal = "removed=[";
83 for (T addr : removed) retVal += addr.toString() + ",";
84 retVal += "] added=[";
85 for (T addr : added) retVal += addr.toString() + ",";
Wink Savillee8222252011-07-13 13:44:13 -070086 retVal += "]";
87 return retVal;
88 }
89 }
90
Robert Greenwalt37e65eb2010-08-30 10:56:47 -070091 public LinkProperties() {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070092 clear();
93 }
94
Robert Greenwalt37e65eb2010-08-30 10:56:47 -070095 // copy constructor instead of clone
96 public LinkProperties(LinkProperties source) {
Irfan Sheriffef6c1432010-08-30 20:37:17 -070097 if (source != null) {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -070098 mIfaceName = source.getInterfaceName();
Robert Greenwalt0d8acea2011-07-28 17:21:25 -070099 for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l);
100 for (InetAddress i : source.getDnses()) mDnses.add(i);
Robert Greenwalt8058f622012-11-09 10:52:27 -0800101 mDomains = source.getDomains();
Robert Greenwalt0d8acea2011-07-28 17:21:25 -0700102 for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
Wink Savillebe2b0582011-05-18 15:59:04 -0700103 mHttpProxy = (source.getHttpProxy() == null) ?
Robert Greenwalt8058f622012-11-09 10:52:27 -0800104 null : new ProxyProperties(source.getHttpProxy());
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800105 for (LinkProperties l: source.mStackedLinks.values()) {
106 addStackedLink(l);
107 }
sy.yun9d9b74a2013-09-02 05:24:09 +0900108 setMtu(source.getMtu());
Irfan Sheriffef6c1432010-08-30 20:37:17 -0700109 }
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700110 }
111
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700112 public void setInterfaceName(String iface) {
113 mIfaceName = iface;
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800114 ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size());
115 for (RouteInfo route : mRoutes) {
116 newRoutes.add(routeWithInterface(route));
117 }
118 mRoutes = newRoutes;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700119 }
120
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700121 public String getInterfaceName() {
122 return mIfaceName;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700123 }
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700124
Lorenzo Colitti4aa9bcf2013-03-20 19:22:58 +0900125 public Collection<String> getAllInterfaceNames() {
126 Collection interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1);
Robert Greenwalt55187f12013-03-22 12:00:17 -0700127 if (mIfaceName != null) interfaceNames.add(new String(mIfaceName));
Lorenzo Colitti4aa9bcf2013-03-20 19:22:58 +0900128 for (LinkProperties stacked: mStackedLinks.values()) {
129 interfaceNames.addAll(stacked.getAllInterfaceNames());
130 }
131 return interfaceNames;
132 }
133
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900134 /**
135 * Returns all the addresses on this link.
136 */
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700137 public Collection<InetAddress> getAddresses() {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700138 Collection<InetAddress> addresses = new ArrayList<InetAddress>();
139 for (LinkAddress linkAddress : mLinkAddresses) {
140 addresses.add(linkAddress.getAddress());
141 }
142 return Collections.unmodifiableCollection(addresses);
143 }
144
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900145 /**
146 * Returns all the addresses on this link and all the links stacked above it.
147 */
148 public Collection<InetAddress> getAllAddresses() {
149 Collection<InetAddress> addresses = new ArrayList<InetAddress>();
150 for (LinkAddress linkAddress : mLinkAddresses) {
151 addresses.add(linkAddress.getAddress());
152 }
153 for (LinkProperties stacked: mStackedLinks.values()) {
154 addresses.addAll(stacked.getAllAddresses());
155 }
156 return addresses;
157 }
158
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900159 /**
160 * Adds a link address if it does not exist, or update it if it does.
161 * @param address The {@code LinkAddress} to add.
162 * @return true if the address was added, false if it already existed.
163 */
164 public boolean addLinkAddress(LinkAddress address) {
165 // TODO: when the LinkAddress has other attributes beyond the
166 // address and the prefix length, update them here.
167 if (address != null && !mLinkAddresses.contains(address)) {
168 mLinkAddresses.add(address);
169 return true;
170 }
171 return false;
172 }
173
174 /**
175 * Removes a link address.
176 * @param address The {@code LinkAddress} to remove.
177 * @return true if the address was removed, false if it did not exist.
178 */
179 public boolean removeLinkAddress(LinkAddress toRemove) {
180 return mLinkAddresses.remove(toRemove);
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700181 }
182
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900183 /**
184 * Returns all the addresses on this link.
185 */
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700186 public Collection<LinkAddress> getLinkAddresses() {
187 return Collections.unmodifiableCollection(mLinkAddresses);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700188 }
189
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900190 /**
191 * Returns all the addresses on this link and all the links stacked above it.
192 */
193 public Collection<LinkAddress> getAllLinkAddresses() {
194 Collection<LinkAddress> addresses = new ArrayList<LinkAddress>();
195 addresses.addAll(mLinkAddresses);
196 for (LinkProperties stacked: mStackedLinks.values()) {
197 addresses.addAll(stacked.getAllLinkAddresses());
198 }
199 return addresses;
200 }
201
Lorenzo Colitti22f407b2013-08-23 20:54:49 +0900202 /**
203 * Replaces the LinkAddresses on this link with the given collection of addresses.
204 */
205 public void setLinkAddresses(Collection<LinkAddress> addresses) {
206 mLinkAddresses.clear();
207 for (LinkAddress address: addresses) {
208 addLinkAddress(address);
209 }
210 }
211
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700212 public void addDns(InetAddress dns) {
Robert Greenwalt04cac402011-03-02 17:03:37 -0800213 if (dns != null) mDnses.add(dns);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700214 }
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700215
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700216 public Collection<InetAddress> getDnses() {
217 return Collections.unmodifiableCollection(mDnses);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700218 }
219
Robert Greenwalt8058f622012-11-09 10:52:27 -0800220 public String getDomains() {
221 return mDomains;
222 }
223
224 public void setDomains(String domains) {
225 mDomains = domains;
226 }
227
sy.yun9d9b74a2013-09-02 05:24:09 +0900228 public void setMtu(int mtu) {
229 mMtu = mtu;
230 }
231
232 public int getMtu() {
233 return mMtu;
234 }
235
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800236 private RouteInfo routeWithInterface(RouteInfo route) {
237 return new RouteInfo(
238 route.getDestination(),
239 route.getGateway(),
240 mIfaceName);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700241 }
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800242
243 public void addRoute(RouteInfo route) {
244 if (route != null) {
245 String routeIface = route.getInterface();
246 if (routeIface != null && !routeIface.equals(mIfaceName)) {
Lorenzo Colitti1994bc12013-03-08 19:11:40 -0800247 throw new IllegalArgumentException(
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800248 "Route added with non-matching interface: " + routeIface +
Lorenzo Colitti1994bc12013-03-08 19:11:40 -0800249 " vs. " + mIfaceName);
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800250 }
251 mRoutes.add(routeWithInterface(route));
252 }
253 }
254
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800255 /**
256 * Returns all the routes on this link.
257 */
Robert Greenwaltaa70f102011-04-28 14:28:50 -0700258 public Collection<RouteInfo> getRoutes() {
259 return Collections.unmodifiableCollection(mRoutes);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700260 }
261
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800262 /**
263 * Returns all the routes on this link and all the links stacked above it.
264 */
265 public Collection<RouteInfo> getAllRoutes() {
266 Collection<RouteInfo> routes = new ArrayList();
267 routes.addAll(mRoutes);
268 for (LinkProperties stacked: mStackedLinks.values()) {
269 routes.addAll(stacked.getAllRoutes());
270 }
Robert Greenwalt6629bcd2013-03-15 11:28:50 -0700271 return routes;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800272 }
273
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700274 public void setHttpProxy(ProxyProperties proxy) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700275 mHttpProxy = proxy;
276 }
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700277 public ProxyProperties getHttpProxy() {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700278 return mHttpProxy;
279 }
280
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800281 /**
282 * Adds a stacked link.
283 *
284 * If there is already a stacked link with the same interfacename as link,
285 * that link is replaced with link. Otherwise, link is added to the list
286 * of stacked links. If link is null, nothing changes.
287 *
288 * @param link The link to add.
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900289 * @return true if the link was stacked, false otherwise.
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800290 */
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900291 public boolean addStackedLink(LinkProperties link) {
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800292 if (link != null && link.getInterfaceName() != null) {
293 mStackedLinks.put(link.getInterfaceName(), link);
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900294 return true;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800295 }
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900296 return false;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800297 }
298
299 /**
300 * Removes a stacked link.
301 *
302 * If there a stacked link with the same interfacename as link, it is
303 * removed. Otherwise, nothing changes.
304 *
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900305 * @param link The link to remove.
306 * @return true if the link was removed, false otherwise.
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800307 */
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900308 public boolean removeStackedLink(LinkProperties link) {
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800309 if (link != null && link.getInterfaceName() != null) {
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900310 LinkProperties removed = mStackedLinks.remove(link.getInterfaceName());
311 return removed != null;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800312 }
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900313 return false;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800314 }
315
316 /**
317 * Returns all the links stacked on top of this link.
318 */
319 public Collection<LinkProperties> getStackedLinks() {
320 Collection<LinkProperties> stacked = new ArrayList<LinkProperties>();
321 for (LinkProperties link : mStackedLinks.values()) {
322 stacked.add(new LinkProperties(link));
323 }
324 return Collections.unmodifiableCollection(stacked);
325 }
326
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700327 public void clear() {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700328 mIfaceName = null;
Wink Savillee8222252011-07-13 13:44:13 -0700329 mLinkAddresses.clear();
330 mDnses.clear();
Robert Greenwalt8058f622012-11-09 10:52:27 -0800331 mDomains = null;
Wink Savillee8222252011-07-13 13:44:13 -0700332 mRoutes.clear();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700333 mHttpProxy = null;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800334 mStackedLinks.clear();
sy.yun9d9b74a2013-09-02 05:24:09 +0900335 mMtu = 0;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700336 }
337
338 /**
339 * Implement the Parcelable interface
340 * @hide
341 */
342 public int describeContents() {
343 return 0;
344 }
345
Wink Saville1f6408a2010-08-27 11:15:18 -0700346 @Override
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700347 public String toString() {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700348 String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " ");
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700349
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700350 String linkAddresses = "LinkAddresses: [";
John Wang4e900092011-04-04 12:35:42 -0700351 for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ",";
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700352 linkAddresses += "] ";
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700353
354 String dns = "DnsAddresses: [";
Wink Saville1f6408a2010-08-27 11:15:18 -0700355 for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ",";
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700356 dns += "] ";
357
Robert Greenwalt8058f622012-11-09 10:52:27 -0800358 String domainName = "Domains: " + mDomains;
359
sy.yun9d9b74a2013-09-02 05:24:09 +0900360 String mtu = "MTU: " + mMtu;
361
Robert Greenwalt8058f622012-11-09 10:52:27 -0800362 String routes = " Routes: [";
Robert Greenwaltaa70f102011-04-28 14:28:50 -0700363 for (RouteInfo route : mRoutes) routes += route.toString() + ",";
364 routes += "] ";
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700365 String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700366
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800367 String stacked = "";
368 if (mStackedLinks.values().size() > 0) {
369 stacked += " Stacked: [";
370 for (LinkProperties link: mStackedLinks.values()) {
371 stacked += " [" + link.toString() + " ],";
372 }
373 stacked += "] ";
374 }
sy.yun9d9b74a2013-09-02 05:24:09 +0900375 return "{" + ifaceName + linkAddresses + routes + dns + domainName + mtu
376 + proxy + stacked + "}";
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800377 }
378
379 /**
380 * Returns true if this link has an IPv4 address.
381 *
382 * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
383 */
384 public boolean hasIPv4Address() {
385 for (LinkAddress address : mLinkAddresses) {
386 if (address.getAddress() instanceof Inet4Address) {
387 return true;
388 }
389 }
390 return false;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700391 }
392
Wink Savillee8222252011-07-13 13:44:13 -0700393 /**
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900394 * Returns true if this link has an IPv6 address.
395 *
396 * @return {@code true} if there is an IPv6 address, {@code false} otherwise.
397 */
398 public boolean hasIPv6Address() {
399 for (LinkAddress address : mLinkAddresses) {
400 if (address.getAddress() instanceof Inet6Address) {
401 return true;
402 }
403 }
404 return false;
405 }
406
407 /**
Wink Savillee8222252011-07-13 13:44:13 -0700408 * Compares this {@code LinkProperties} interface name against the target
409 *
410 * @param target LinkProperties to compare.
411 * @return {@code true} if both are identical, {@code false} otherwise.
412 */
413 public boolean isIdenticalInterfaceName(LinkProperties target) {
414 return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
415 }
416
417 /**
Robert Greenwalt4717c262012-10-31 14:32:53 -0700418 * Compares this {@code LinkProperties} interface addresses against the target
Wink Savillee8222252011-07-13 13:44:13 -0700419 *
420 * @param target LinkProperties to compare.
421 * @return {@code true} if both are identical, {@code false} otherwise.
422 */
423 public boolean isIdenticalAddresses(LinkProperties target) {
424 Collection<InetAddress> targetAddresses = target.getAddresses();
425 Collection<InetAddress> sourceAddresses = getAddresses();
426 return (sourceAddresses.size() == targetAddresses.size()) ?
427 sourceAddresses.containsAll(targetAddresses) : false;
428 }
429
430 /**
431 * Compares this {@code LinkProperties} DNS addresses against the target
432 *
433 * @param target LinkProperties to compare.
434 * @return {@code true} if both are identical, {@code false} otherwise.
435 */
436 public boolean isIdenticalDnses(LinkProperties target) {
437 Collection<InetAddress> targetDnses = target.getDnses();
Robert Greenwalt8058f622012-11-09 10:52:27 -0800438 String targetDomains = target.getDomains();
439 if (mDomains == null) {
440 if (targetDomains != null) return false;
441 } else {
442 if (mDomains.equals(targetDomains) == false) return false;
443 }
Wink Savillee8222252011-07-13 13:44:13 -0700444 return (mDnses.size() == targetDnses.size()) ?
445 mDnses.containsAll(targetDnses) : false;
446 }
447
448 /**
449 * Compares this {@code LinkProperties} Routes against the target
450 *
451 * @param target LinkProperties to compare.
452 * @return {@code true} if both are identical, {@code false} otherwise.
453 */
454 public boolean isIdenticalRoutes(LinkProperties target) {
455 Collection<RouteInfo> targetRoutes = target.getRoutes();
456 return (mRoutes.size() == targetRoutes.size()) ?
457 mRoutes.containsAll(targetRoutes) : false;
458 }
459
460 /**
461 * Compares this {@code LinkProperties} HttpProxy against the target
462 *
463 * @param target LinkProperties to compare.
464 * @return {@code true} if both are identical, {@code false} otherwise.
465 */
466 public boolean isIdenticalHttpProxy(LinkProperties target) {
467 return getHttpProxy() == null ? target.getHttpProxy() == null :
468 getHttpProxy().equals(target.getHttpProxy());
469 }
John Wang4e900092011-04-04 12:35:42 -0700470
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800471 /**
472 * Compares this {@code LinkProperties} stacked links against the target
473 *
474 * @param target LinkProperties to compare.
475 * @return {@code true} if both are identical, {@code false} otherwise.
476 */
477 public boolean isIdenticalStackedLinks(LinkProperties target) {
Lorenzo Colitti213f98b2013-04-01 10:47:43 +0900478 if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800479 return false;
480 }
481 for (LinkProperties stacked : mStackedLinks.values()) {
482 // Hashtable values can never be null.
483 String iface = stacked.getInterfaceName();
484 if (!stacked.equals(target.mStackedLinks.get(iface))) {
485 return false;
486 }
487 }
488 return true;
489 }
490
sy.yun9d9b74a2013-09-02 05:24:09 +0900491 /**
492 * Compares this {@code LinkProperties} MTU against the target
493 *
Ying Wangd57de6a2013-09-06 22:53:16 -0700494 * @param target LinkProperties to compare.
sy.yun9d9b74a2013-09-02 05:24:09 +0900495 * @return {@code true} if both are identical, {@code false} otherwise.
496 */
497 public boolean isIdenticalMtu(LinkProperties target) {
498 return getMtu() == target.getMtu();
499 }
500
John Wang4e900092011-04-04 12:35:42 -0700501 @Override
502 /**
503 * Compares this {@code LinkProperties} instance against the target
504 * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
505 * all their fields are equal in values.
506 *
507 * For collection fields, such as mDnses, containsAll() is used to check
508 * if two collections contains the same elements, independent of order.
509 * There are two thoughts regarding containsAll()
510 * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
511 * 2. Worst case performance is O(n^2).
512 *
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800513 * This method does not check that stacked interfaces are equal, because
514 * stacked interfaces are not so much a property of the link as a
515 * description of connections between links.
516 *
John Wang4e900092011-04-04 12:35:42 -0700517 * @param obj the object to be tested for equality.
518 * @return {@code true} if both objects are equal, {@code false} otherwise.
519 */
520 public boolean equals(Object obj) {
521 if (this == obj) return true;
522
523 if (!(obj instanceof LinkProperties)) return false;
524
John Wang4e900092011-04-04 12:35:42 -0700525 LinkProperties target = (LinkProperties) obj;
526
Wink Savillee8222252011-07-13 13:44:13 -0700527 return isIdenticalInterfaceName(target) &&
528 isIdenticalAddresses(target) &&
529 isIdenticalDnses(target) &&
530 isIdenticalRoutes(target) &&
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800531 isIdenticalHttpProxy(target) &&
sy.yun9d9b74a2013-09-02 05:24:09 +0900532 isIdenticalStackedLinks(target) &&
533 isIdenticalMtu(target);
Wink Savillee8222252011-07-13 13:44:13 -0700534 }
John Wang4e900092011-04-04 12:35:42 -0700535
Wink Savillee8222252011-07-13 13:44:13 -0700536 /**
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900537 * Compares the addresses in this LinkProperties with another
538 * LinkProperties, examining only addresses on the base link.
Wink Savillee8222252011-07-13 13:44:13 -0700539 *
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900540 * @param target a LinkProperties with the new list of addresses
541 * @return the differences between the addresses.
Wink Savillee8222252011-07-13 13:44:13 -0700542 */
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700543 public CompareResult<LinkAddress> compareAddresses(LinkProperties target) {
Wink Savillee8222252011-07-13 13:44:13 -0700544 /*
545 * Duplicate the LinkAddresses into removed, we will be removing
546 * address which are common between mLinkAddresses and target
547 * leaving the addresses that are different. And address which
548 * are in target but not in mLinkAddresses are placed in the
549 * addedAddresses.
550 */
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700551 CompareResult<LinkAddress> result = new CompareResult<LinkAddress>();
Wink Savillee8222252011-07-13 13:44:13 -0700552 result.removed = new ArrayList<LinkAddress>(mLinkAddresses);
553 result.added.clear();
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700554 if (target != null) {
555 for (LinkAddress newAddress : target.getLinkAddresses()) {
556 if (! result.removed.remove(newAddress)) {
557 result.added.add(newAddress);
558 }
Wink Savillee8222252011-07-13 13:44:13 -0700559 }
560 }
561 return result;
John Wang4e900092011-04-04 12:35:42 -0700562 }
563
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700564 /**
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900565 * Compares the DNS addresses in this LinkProperties with another
566 * LinkProperties, examining only DNS addresses on the base link.
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700567 *
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900568 * @param target a LinkProperties with the new list of dns addresses
569 * @return the differences between the DNS addresses.
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700570 */
571 public CompareResult<InetAddress> compareDnses(LinkProperties target) {
572 /*
573 * Duplicate the InetAddresses into removed, we will be removing
574 * dns address which are common between mDnses and target
575 * leaving the addresses that are different. And dns address which
576 * are in target but not in mDnses are placed in the
577 * addedAddresses.
578 */
579 CompareResult<InetAddress> result = new CompareResult<InetAddress>();
580
581 result.removed = new ArrayList<InetAddress>(mDnses);
582 result.added.clear();
583 if (target != null) {
584 for (InetAddress newAddress : target.getDnses()) {
585 if (! result.removed.remove(newAddress)) {
586 result.added.add(newAddress);
587 }
588 }
589 }
590 return result;
591 }
592
593 /**
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900594 * Compares all routes in this LinkProperties with another LinkProperties,
595 * examining both the the base link and all stacked links.
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700596 *
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900597 * @param target a LinkProperties with the new list of routes
598 * @return the differences between the routes.
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700599 */
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900600 public CompareResult<RouteInfo> compareAllRoutes(LinkProperties target) {
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700601 /*
602 * Duplicate the RouteInfos into removed, we will be removing
Lorenzo Colitti1994bc12013-03-08 19:11:40 -0800603 * routes which are common between mRoutes and target
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700604 * leaving the routes that are different. And route address which
605 * are in target but not in mRoutes are placed in added.
606 */
607 CompareResult<RouteInfo> result = new CompareResult<RouteInfo>();
608
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800609 result.removed = getAllRoutes();
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700610 result.added.clear();
611 if (target != null) {
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800612 for (RouteInfo r : target.getAllRoutes()) {
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700613 if (! result.removed.remove(r)) {
614 result.added.add(r);
615 }
616 }
617 }
618 return result;
619 }
620
621
John Wang4e900092011-04-04 12:35:42 -0700622 @Override
623 /**
624 * generate hashcode based on significant fields
625 * Equal objects must produce the same hash code, while unequal objects
626 * may have the same hash codes.
627 */
628 public int hashCode() {
629 return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
630 + mLinkAddresses.size() * 31
631 + mDnses.size() * 37
Robert Greenwalt8058f622012-11-09 10:52:27 -0800632 + ((null == mDomains) ? 0 : mDomains.hashCode())
Robert Greenwaltaa70f102011-04-28 14:28:50 -0700633 + mRoutes.size() * 41
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800634 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
sy.yun9d9b74a2013-09-02 05:24:09 +0900635 + mStackedLinks.hashCode() * 47)
636 + mMtu * 51;
John Wang4e900092011-04-04 12:35:42 -0700637 }
638
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700639 /**
640 * Implement the Parcelable interface.
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700641 */
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700642 public void writeToParcel(Parcel dest, int flags) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700643 dest.writeString(getInterfaceName());
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700644 dest.writeInt(mLinkAddresses.size());
645 for(LinkAddress linkAddress : mLinkAddresses) {
646 dest.writeParcelable(linkAddress, flags);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700647 }
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700648
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700649 dest.writeInt(mDnses.size());
650 for(InetAddress d : mDnses) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700651 dest.writeByteArray(d.getAddress());
652 }
Robert Greenwalt8058f622012-11-09 10:52:27 -0800653 dest.writeString(mDomains);
sy.yun9d9b74a2013-09-02 05:24:09 +0900654 dest.writeInt(mMtu);
Robert Greenwaltaa70f102011-04-28 14:28:50 -0700655 dest.writeInt(mRoutes.size());
656 for(RouteInfo route : mRoutes) {
657 dest.writeParcelable(route, flags);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700658 }
Robert Greenwalt992564e2011-02-09 13:56:06 -0800659
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700660 if (mHttpProxy != null) {
661 dest.writeByte((byte)1);
662 dest.writeParcelable(mHttpProxy, flags);
663 } else {
664 dest.writeByte((byte)0);
665 }
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800666 ArrayList<LinkProperties> stackedLinks = new ArrayList(mStackedLinks.values());
667 dest.writeList(stackedLinks);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700668 }
669
670 /**
671 * Implement the Parcelable interface.
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700672 */
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700673 public static final Creator<LinkProperties> CREATOR =
674 new Creator<LinkProperties>() {
675 public LinkProperties createFromParcel(Parcel in) {
676 LinkProperties netProp = new LinkProperties();
Robert Greenwalt4717c262012-10-31 14:32:53 -0700677
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700678 String iface = in.readString();
679 if (iface != null) {
Robert Greenwalt4717c262012-10-31 14:32:53 -0700680 netProp.setInterfaceName(iface);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700681 }
682 int addressCount = in.readInt();
683 for (int i=0; i<addressCount; i++) {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700684 netProp.addLinkAddress((LinkAddress)in.readParcelable(null));
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700685 }
686 addressCount = in.readInt();
687 for (int i=0; i<addressCount; i++) {
688 try {
Irfan Sheriff1cf56ab2010-08-04 15:15:49 -0700689 netProp.addDns(InetAddress.getByAddress(in.createByteArray()));
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700690 } catch (UnknownHostException e) { }
691 }
Robert Greenwalt8058f622012-11-09 10:52:27 -0800692 netProp.setDomains(in.readString());
sy.yun9d9b74a2013-09-02 05:24:09 +0900693 netProp.setMtu(in.readInt());
Robert Greenwalt992564e2011-02-09 13:56:06 -0800694 addressCount = in.readInt();
695 for (int i=0; i<addressCount; i++) {
Robert Greenwaltaa70f102011-04-28 14:28:50 -0700696 netProp.addRoute((RouteInfo)in.readParcelable(null));
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700697 }
698 if (in.readByte() == 1) {
699 netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
700 }
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800701 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
702 in.readList(stackedLinks, LinkProperties.class.getClassLoader());
703 for (LinkProperties stackedLink: stackedLinks) {
704 netProp.addStackedLink(stackedLink);
705 }
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700706 return netProp;
707 }
708
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700709 public LinkProperties[] newArray(int size) {
710 return new LinkProperties[size];
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700711 }
712 };
713}