LinkProperties.java revision 4f05d5529625fd2f0ad13ff9974c338d2f847934
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 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 19import android.net.ProxyInfo; 20import android.os.Parcelable; 21import android.os.Parcel; 22import android.text.TextUtils; 23 24import java.net.InetAddress; 25import java.net.Inet4Address; 26import java.net.Inet6Address; 27 28import java.net.UnknownHostException; 29import java.util.ArrayList; 30import java.util.Collection; 31import java.util.Collections; 32import java.util.Hashtable; 33 34/** 35 * Describes the properties of a network link. 36 * 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 and one 40 * network interface. 41 * 42 * Note that this is just a holder of data. Modifying it 43 * does not affect live networks. 44 * 45 */ 46public class LinkProperties implements Parcelable { 47 // The interface described by the network link. 48 private String mIfaceName; 49 private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>(); 50 private ArrayList<InetAddress> mDnses = new ArrayList<InetAddress>(); 51 private String mDomains; 52 private ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 53 private ProxyInfo mHttpProxy; 54 private int mMtu; 55 56 // Stores the properties of links that are "stacked" above this link. 57 // Indexed by interface name to allow modification and to prevent duplicates being added. 58 private Hashtable<String, LinkProperties> mStackedLinks = 59 new Hashtable<String, LinkProperties>(); 60 61 // @hide 62 public static class CompareResult<T> { 63 public Collection<T> removed = new ArrayList<T>(); 64 public Collection<T> added = new ArrayList<T>(); 65 66 @Override 67 public String toString() { 68 String retVal = "removed=["; 69 for (T addr : removed) retVal += addr.toString() + ","; 70 retVal += "] added=["; 71 for (T addr : added) retVal += addr.toString() + ","; 72 retVal += "]"; 73 return retVal; 74 } 75 } 76 77 public LinkProperties() { 78 } 79 80 public LinkProperties(LinkProperties source) { 81 if (source != null) { 82 mIfaceName = source.getInterfaceName(); 83 for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l); 84 for (InetAddress i : source.getDnses()) mDnses.add(i); 85 mDomains = source.getDomains(); 86 for (RouteInfo r : source.getRoutes()) mRoutes.add(r); 87 mHttpProxy = (source.getHttpProxy() == null) ? 88 null : new ProxyInfo(source.getHttpProxy()); 89 for (LinkProperties l: source.mStackedLinks.values()) { 90 addStackedLink(l); 91 } 92 setMtu(source.getMtu()); 93 } 94 } 95 96 /** 97 * Sets the interface name for this link. All {@link RouteInfo} already set for this 98 * will have their interface changed to match this new value. 99 * 100 * @param iface The name of the network interface used for this link. 101 */ 102 public void setInterfaceName(String iface) { 103 mIfaceName = iface; 104 ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size()); 105 for (RouteInfo route : mRoutes) { 106 newRoutes.add(routeWithInterface(route)); 107 } 108 mRoutes = newRoutes; 109 } 110 111 /** 112 * Gets the interface name for this link. May be {@code null} if not set. 113 * 114 * @return The interface name set for this link or {@code null}. 115 */ 116 public String getInterfaceName() { 117 return mIfaceName; 118 } 119 120 // @hide 121 public Collection<String> getAllInterfaceNames() { 122 Collection interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1); 123 if (mIfaceName != null) interfaceNames.add(new String(mIfaceName)); 124 for (LinkProperties stacked: mStackedLinks.values()) { 125 interfaceNames.addAll(stacked.getAllInterfaceNames()); 126 } 127 return interfaceNames; 128 } 129 130 /** 131 * Returns all the addresses on this link. We often think of a link having a single address, 132 * however, particularly with Ipv6 several addresses are typical. Note that the 133 * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include 134 * prefix lengths for each address. This is a simplified utility alternative to 135 * {@link LinkProperties#getLinkAddresses}. 136 * 137 * @return An umodifiable {@link Collection} of {@link InetAddress} for this link. 138 * @hide 139 */ 140 public Collection<InetAddress> getAddresses() { 141 Collection<InetAddress> addresses = new ArrayList<InetAddress>(); 142 for (LinkAddress linkAddress : mLinkAddresses) { 143 addresses.add(linkAddress.getAddress()); 144 } 145 return Collections.unmodifiableCollection(addresses); 146 } 147 148 /** 149 * Returns all the addresses on this link and all the links stacked above it. 150 * @hide 151 */ 152 public Collection<InetAddress> getAllAddresses() { 153 Collection<InetAddress> addresses = new ArrayList<InetAddress>(); 154 for (LinkAddress linkAddress : mLinkAddresses) { 155 addresses.add(linkAddress.getAddress()); 156 } 157 for (LinkProperties stacked: mStackedLinks.values()) { 158 addresses.addAll(stacked.getAllAddresses()); 159 } 160 return addresses; 161 } 162 163 private int findLinkAddressIndex(LinkAddress address) { 164 for (int i = 0; i < mLinkAddresses.size(); i++) { 165 if (mLinkAddresses.get(i).isSameAddressAs(address)) { 166 return i; 167 } 168 } 169 return -1; 170 } 171 172 /** 173 * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the 174 * same address/prefix does not already exist. If it does exist it is replaced. 175 * @param address The {@code LinkAddress} to add. 176 * @return true if {@code address} was added or updated, false otherwise. 177 */ 178 public boolean addLinkAddress(LinkAddress address) { 179 if (address == null) { 180 return false; 181 } 182 int i = findLinkAddressIndex(address); 183 if (i < 0) { 184 // Address was not present. Add it. 185 mLinkAddresses.add(address); 186 return true; 187 } else if (mLinkAddresses.get(i).equals(address)) { 188 // Address was present and has same properties. Do nothing. 189 return false; 190 } else { 191 // Address was present and has different properties. Update it. 192 mLinkAddresses.set(i, address); 193 return true; 194 } 195 } 196 197 /** 198 * Removes a {@link LinkAddress} from this {@code LinkProperties}. Specifically, matches 199 * and {@link LinkAddress} with the same address and prefix. 200 * 201 * @param toRemove A {@link LinkAddress} specifying the address to remove. 202 * @return true if the address was removed, false if it did not exist. 203 */ 204 public boolean removeLinkAddress(LinkAddress toRemove) { 205 int i = findLinkAddressIndex(toRemove); 206 if (i >= 0) { 207 mLinkAddresses.remove(i); 208 return true; 209 } 210 return false; 211 } 212 213 /** 214 * Returns all the {@link LinkAddress} on this link. Typically a link will have 215 * one IPv4 address and one or more IPv6 addresses. 216 * 217 * @return An unmodifiable {@link Collection} of {@link LinkAddress} for this link. 218 */ 219 public Collection<LinkAddress> getLinkAddresses() { 220 return Collections.unmodifiableCollection(mLinkAddresses); 221 } 222 223 /** 224 * Returns all the addresses on this link and all the links stacked above it. 225 * @hide 226 */ 227 public Collection<LinkAddress> getAllLinkAddresses() { 228 Collection<LinkAddress> addresses = new ArrayList<LinkAddress>(); 229 addresses.addAll(mLinkAddresses); 230 for (LinkProperties stacked: mStackedLinks.values()) { 231 addresses.addAll(stacked.getAllLinkAddresses()); 232 } 233 return addresses; 234 } 235 236 /** 237 * Replaces the {@link LinkAddress} in this {@code LinkProperties} with 238 * the given {@link Collection} of {@link LinkAddress}. 239 * 240 * @param addresses The {@link Collection} of {@link LinkAddress} to set in this 241 * object. 242 */ 243 public void setLinkAddresses(Collection<LinkAddress> addresses) { 244 mLinkAddresses.clear(); 245 for (LinkAddress address: addresses) { 246 addLinkAddress(address); 247 } 248 } 249 250 /** 251 * Adds the given {@link InetAddress} to the list of DNS servers. 252 * 253 * @param dns The {@link InetAddress} to add to the list of DNS servers. 254 */ 255 public void addDns(InetAddress dns) { 256 if (dns != null) mDnses.add(dns); 257 } 258 259 /** 260 * Returns all the {@link LinkAddress} for DNS servers on this link. 261 * 262 * @return An umodifiable {@link Collection} of {@link InetAddress} for DNS servers on 263 * this link. 264 */ 265 public Collection<InetAddress> getDnses() { 266 return Collections.unmodifiableCollection(mDnses); 267 } 268 269 /** 270 * Sets the DNS domain search path used on this link. 271 * 272 * @param domains A {@link String} listing in priority order the comma separated 273 * domains to search when resolving host names on this link. 274 */ 275 public void setDomains(String domains) { 276 mDomains = domains; 277 } 278 279 /** 280 * Get the DNS domains search path set for this link. 281 * 282 * @return A {@link String} containing the comma separated domains to search when resolving 283 * host names on this link. 284 */ 285 public String getDomains() { 286 return mDomains; 287 } 288 289 /** 290 * Sets the Maximum Transmission Unit size to use on this link. This should not be used 291 * unless the system default (1500) is incorrect. Values less than 68 or greater than 292 * 10000 will be ignored. 293 * 294 * @param mtu The MTU to use for this link. 295 * @hide 296 */ 297 public void setMtu(int mtu) { 298 mMtu = mtu; 299 } 300 301 /** 302 * Gets any non-default MTU size set for this link. Note that if the default is being used 303 * this will return 0. 304 * 305 * @return The mtu value set for this link. 306 * @hide 307 */ 308 public int getMtu() { 309 return mMtu; 310 } 311 312 private RouteInfo routeWithInterface(RouteInfo route) { 313 return new RouteInfo( 314 route.getDestination(), 315 route.getGateway(), 316 mIfaceName); 317 } 318 319 /** 320 * Adds a {@link RouteInfo} to this {@code LinkProperties}. If the {@link RouteInfo} 321 * had an interface name set and that differs from the interface set for this 322 * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown. The 323 * proper course is to add either un-named or properly named {@link RouteInfo}. 324 * 325 * @param route A {@link RouteInfo} to add to this object. 326 */ 327 public void addRoute(RouteInfo route) { 328 if (route != null) { 329 String routeIface = route.getInterface(); 330 if (routeIface != null && !routeIface.equals(mIfaceName)) { 331 throw new IllegalArgumentException( 332 "Route added with non-matching interface: " + routeIface + 333 " vs. " + mIfaceName); 334 } 335 mRoutes.add(routeWithInterface(route)); 336 } 337 } 338 339 /** 340 * Returns all the {@link RouteInfo} set on this link. 341 * 342 * @return An unmodifiable {@link Collection} of {@link RouteInfo} for this link. 343 */ 344 public Collection<RouteInfo> getRoutes() { 345 return Collections.unmodifiableCollection(mRoutes); 346 } 347 348 /** 349 * Returns all the routes on this link and all the links stacked above it. 350 * @hide 351 */ 352 public Collection<RouteInfo> getAllRoutes() { 353 Collection<RouteInfo> routes = new ArrayList(); 354 routes.addAll(mRoutes); 355 for (LinkProperties stacked: mStackedLinks.values()) { 356 routes.addAll(stacked.getAllRoutes()); 357 } 358 return routes; 359 } 360 361 /** 362 * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none. 363 * Note that Http Proxies are only a hint - the system recommends their use, but it does 364 * not enforce it and applications may ignore them. 365 * 366 * @param proxy A {@link ProxyInfo} defining the Http Proxy to use on this link. 367 */ 368 public void setHttpProxy(ProxyInfo proxy) { 369 mHttpProxy = proxy; 370 } 371 372 /** 373 * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link. 374 * 375 * @return The {@link ProxyInfo} set on this link 376 */ 377 public ProxyInfo getHttpProxy() { 378 return mHttpProxy; 379 } 380 381 /** 382 * Adds a stacked link. 383 * 384 * If there is already a stacked link with the same interfacename as link, 385 * that link is replaced with link. Otherwise, link is added to the list 386 * of stacked links. If link is null, nothing changes. 387 * 388 * @param link The link to add. 389 * @return true if the link was stacked, false otherwise. 390 * @hide 391 */ 392 public boolean addStackedLink(LinkProperties link) { 393 if (link != null && link.getInterfaceName() != null) { 394 mStackedLinks.put(link.getInterfaceName(), link); 395 return true; 396 } 397 return false; 398 } 399 400 /** 401 * Removes a stacked link. 402 * 403 * If there a stacked link with the same interfacename as link, it is 404 * removed. Otherwise, nothing changes. 405 * 406 * @param link The link to remove. 407 * @return true if the link was removed, false otherwise. 408 * @hide 409 */ 410 public boolean removeStackedLink(LinkProperties link) { 411 if (link != null && link.getInterfaceName() != null) { 412 LinkProperties removed = mStackedLinks.remove(link.getInterfaceName()); 413 return removed != null; 414 } 415 return false; 416 } 417 418 /** 419 * Returns all the links stacked on top of this link. 420 * @hide 421 */ 422 public Collection<LinkProperties> getStackedLinks() { 423 Collection<LinkProperties> stacked = new ArrayList<LinkProperties>(); 424 for (LinkProperties link : mStackedLinks.values()) { 425 stacked.add(new LinkProperties(link)); 426 } 427 return Collections.unmodifiableCollection(stacked); 428 } 429 430 /** 431 * Clears this object to its initial state. 432 */ 433 public void clear() { 434 mIfaceName = null; 435 mLinkAddresses.clear(); 436 mDnses.clear(); 437 mDomains = null; 438 mRoutes.clear(); 439 mHttpProxy = null; 440 mStackedLinks.clear(); 441 mMtu = 0; 442 } 443 444 /** 445 * Implement the Parcelable interface 446 * @hide 447 */ 448 public int describeContents() { 449 return 0; 450 } 451 452 @Override 453 public String toString() { 454 String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " "); 455 456 String linkAddresses = "LinkAddresses: ["; 457 for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ","; 458 linkAddresses += "] "; 459 460 String dns = "DnsAddresses: ["; 461 for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ","; 462 dns += "] "; 463 464 String domainName = "Domains: " + mDomains; 465 466 String mtu = "MTU: " + mMtu; 467 468 String routes = " Routes: ["; 469 for (RouteInfo route : mRoutes) routes += route.toString() + ","; 470 routes += "] "; 471 String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " "); 472 473 String stacked = ""; 474 if (mStackedLinks.values().size() > 0) { 475 stacked += " Stacked: ["; 476 for (LinkProperties link: mStackedLinks.values()) { 477 stacked += " [" + link.toString() + " ],"; 478 } 479 stacked += "] "; 480 } 481 return "{" + ifaceName + linkAddresses + routes + dns + domainName + mtu 482 + proxy + stacked + "}"; 483 } 484 485 /** 486 * Returns true if this link has an IPv4 address. 487 * 488 * @return {@code true} if there is an IPv4 address, {@code false} otherwise. 489 */ 490 public boolean hasIPv4Address() { 491 for (LinkAddress address : mLinkAddresses) { 492 if (address.getAddress() instanceof Inet4Address) { 493 return true; 494 } 495 } 496 return false; 497 } 498 499 /** 500 * Returns true if this link has an IPv6 address. 501 * 502 * @return {@code true} if there is an IPv6 address, {@code false} otherwise. 503 */ 504 public boolean hasIPv6Address() { 505 for (LinkAddress address : mLinkAddresses) { 506 if (address.getAddress() instanceof Inet6Address) { 507 return true; 508 } 509 } 510 return false; 511 } 512 513 /** 514 * Compares this {@code LinkProperties} interface name against the target 515 * 516 * @param target LinkProperties to compare. 517 * @return {@code true} if both are identical, {@code false} otherwise. 518 * @hide 519 */ 520 public boolean isIdenticalInterfaceName(LinkProperties target) { 521 return TextUtils.equals(getInterfaceName(), target.getInterfaceName()); 522 } 523 524 /** 525 * Compares this {@code LinkProperties} interface addresses against the target 526 * 527 * @param target LinkProperties to compare. 528 * @return {@code true} if both are identical, {@code false} otherwise. 529 * @hide 530 */ 531 public boolean isIdenticalAddresses(LinkProperties target) { 532 Collection<InetAddress> targetAddresses = target.getAddresses(); 533 Collection<InetAddress> sourceAddresses = getAddresses(); 534 return (sourceAddresses.size() == targetAddresses.size()) ? 535 sourceAddresses.containsAll(targetAddresses) : false; 536 } 537 538 /** 539 * Compares this {@code LinkProperties} DNS addresses against the target 540 * 541 * @param target LinkProperties to compare. 542 * @return {@code true} if both are identical, {@code false} otherwise. 543 * @hide 544 */ 545 public boolean isIdenticalDnses(LinkProperties target) { 546 Collection<InetAddress> targetDnses = target.getDnses(); 547 String targetDomains = target.getDomains(); 548 if (mDomains == null) { 549 if (targetDomains != null) return false; 550 } else { 551 if (mDomains.equals(targetDomains) == false) return false; 552 } 553 return (mDnses.size() == targetDnses.size()) ? 554 mDnses.containsAll(targetDnses) : false; 555 } 556 557 /** 558 * Compares this {@code LinkProperties} Routes against the target 559 * 560 * @param target LinkProperties to compare. 561 * @return {@code true} if both are identical, {@code false} otherwise. 562 * @hide 563 */ 564 public boolean isIdenticalRoutes(LinkProperties target) { 565 Collection<RouteInfo> targetRoutes = target.getRoutes(); 566 return (mRoutes.size() == targetRoutes.size()) ? 567 mRoutes.containsAll(targetRoutes) : false; 568 } 569 570 /** 571 * Compares this {@code LinkProperties} HttpProxy against the target 572 * 573 * @param target LinkProperties to compare. 574 * @return {@code true} if both are identical, {@code false} otherwise. 575 * @hide 576 */ 577 public boolean isIdenticalHttpProxy(LinkProperties target) { 578 return getHttpProxy() == null ? target.getHttpProxy() == null : 579 getHttpProxy().equals(target.getHttpProxy()); 580 } 581 582 /** 583 * Compares this {@code LinkProperties} stacked links against the target 584 * 585 * @param target LinkProperties to compare. 586 * @return {@code true} if both are identical, {@code false} otherwise. 587 * @hide 588 */ 589 public boolean isIdenticalStackedLinks(LinkProperties target) { 590 if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) { 591 return false; 592 } 593 for (LinkProperties stacked : mStackedLinks.values()) { 594 // Hashtable values can never be null. 595 String iface = stacked.getInterfaceName(); 596 if (!stacked.equals(target.mStackedLinks.get(iface))) { 597 return false; 598 } 599 } 600 return true; 601 } 602 603 /** 604 * Compares this {@code LinkProperties} MTU against the target 605 * 606 * @param target LinkProperties to compare. 607 * @return {@code true} if both are identical, {@code false} otherwise. 608 * @hide 609 */ 610 public boolean isIdenticalMtu(LinkProperties target) { 611 return getMtu() == target.getMtu(); 612 } 613 614 @Override 615 /** 616 * Compares this {@code LinkProperties} instance against the target 617 * LinkProperties in {@code obj}. Two LinkPropertieses are equal if 618 * all their fields are equal in values. 619 * 620 * For collection fields, such as mDnses, containsAll() is used to check 621 * if two collections contains the same elements, independent of order. 622 * There are two thoughts regarding containsAll() 623 * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal. 624 * 2. Worst case performance is O(n^2). 625 * 626 * @param obj the object to be tested for equality. 627 * @return {@code true} if both objects are equal, {@code false} otherwise. 628 */ 629 public boolean equals(Object obj) { 630 if (this == obj) return true; 631 632 if (!(obj instanceof LinkProperties)) return false; 633 634 LinkProperties target = (LinkProperties) obj; 635 /** 636 * This method does not check that stacked interfaces are equal, because 637 * stacked interfaces are not so much a property of the link as a 638 * description of connections between links. 639 */ 640 return isIdenticalInterfaceName(target) && 641 isIdenticalAddresses(target) && 642 isIdenticalDnses(target) && 643 isIdenticalRoutes(target) && 644 isIdenticalHttpProxy(target) && 645 isIdenticalStackedLinks(target) && 646 isIdenticalMtu(target); 647 } 648 649 /** 650 * Compares the addresses in this LinkProperties with another 651 * LinkProperties, examining only addresses on the base link. 652 * 653 * @param target a LinkProperties with the new list of addresses 654 * @return the differences between the addresses. 655 * @hide 656 */ 657 public CompareResult<LinkAddress> compareAddresses(LinkProperties target) { 658 /* 659 * Duplicate the LinkAddresses into removed, we will be removing 660 * address which are common between mLinkAddresses and target 661 * leaving the addresses that are different. And address which 662 * are in target but not in mLinkAddresses are placed in the 663 * addedAddresses. 664 */ 665 CompareResult<LinkAddress> result = new CompareResult<LinkAddress>(); 666 result.removed = new ArrayList<LinkAddress>(mLinkAddresses); 667 result.added.clear(); 668 if (target != null) { 669 for (LinkAddress newAddress : target.getLinkAddresses()) { 670 if (! result.removed.remove(newAddress)) { 671 result.added.add(newAddress); 672 } 673 } 674 } 675 return result; 676 } 677 678 /** 679 * Compares the DNS addresses in this LinkProperties with another 680 * LinkProperties, examining only DNS addresses on the base link. 681 * 682 * @param target a LinkProperties with the new list of dns addresses 683 * @return the differences between the DNS addresses. 684 * @hide 685 */ 686 public CompareResult<InetAddress> compareDnses(LinkProperties target) { 687 /* 688 * Duplicate the InetAddresses into removed, we will be removing 689 * dns address which are common between mDnses and target 690 * leaving the addresses that are different. And dns address which 691 * are in target but not in mDnses are placed in the 692 * addedAddresses. 693 */ 694 CompareResult<InetAddress> result = new CompareResult<InetAddress>(); 695 696 result.removed = new ArrayList<InetAddress>(mDnses); 697 result.added.clear(); 698 if (target != null) { 699 for (InetAddress newAddress : target.getDnses()) { 700 if (! result.removed.remove(newAddress)) { 701 result.added.add(newAddress); 702 } 703 } 704 } 705 return result; 706 } 707 708 /** 709 * Compares all routes in this LinkProperties with another LinkProperties, 710 * examining both the the base link and all stacked links. 711 * 712 * @param target a LinkProperties with the new list of routes 713 * @return the differences between the routes. 714 * @hide 715 */ 716 public CompareResult<RouteInfo> compareAllRoutes(LinkProperties target) { 717 /* 718 * Duplicate the RouteInfos into removed, we will be removing 719 * routes which are common between mRoutes and target 720 * leaving the routes that are different. And route address which 721 * are in target but not in mRoutes are placed in added. 722 */ 723 CompareResult<RouteInfo> result = new CompareResult<RouteInfo>(); 724 725 result.removed = getAllRoutes(); 726 result.added.clear(); 727 if (target != null) { 728 for (RouteInfo r : target.getAllRoutes()) { 729 if (! result.removed.remove(r)) { 730 result.added.add(r); 731 } 732 } 733 } 734 return result; 735 } 736 737 /** 738 * Compares all interface names in this LinkProperties with another 739 * LinkProperties, examining both the the base link and all stacked links. 740 * 741 * @param target a LinkProperties with the new list of interface names 742 * @return the differences between the interface names. 743 * @hide 744 */ 745 public CompareResult<String> compareAllInterfaceNames(LinkProperties target) { 746 /* 747 * Duplicate the interface names into removed, we will be removing 748 * interface names which are common between this and target 749 * leaving the interface names that are different. And interface names which 750 * are in target but not in this are placed in added. 751 */ 752 CompareResult<String> result = new CompareResult<String>(); 753 754 result.removed = getAllInterfaceNames(); 755 result.added.clear(); 756 if (target != null) { 757 for (String r : target.getAllInterfaceNames()) { 758 if (! result.removed.remove(r)) { 759 result.added.add(r); 760 } 761 } 762 } 763 return result; 764 } 765 766 767 @Override 768 /** 769 * generate hashcode based on significant fields 770 * Equal objects must produce the same hash code, while unequal objects 771 * may have the same hash codes. 772 */ 773 public int hashCode() { 774 return ((null == mIfaceName) ? 0 : mIfaceName.hashCode() 775 + mLinkAddresses.size() * 31 776 + mDnses.size() * 37 777 + ((null == mDomains) ? 0 : mDomains.hashCode()) 778 + mRoutes.size() * 41 779 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()) 780 + mStackedLinks.hashCode() * 47) 781 + mMtu * 51; 782 } 783 784 /** 785 * Implement the Parcelable interface. 786 */ 787 public void writeToParcel(Parcel dest, int flags) { 788 dest.writeString(getInterfaceName()); 789 dest.writeInt(mLinkAddresses.size()); 790 for(LinkAddress linkAddress : mLinkAddresses) { 791 dest.writeParcelable(linkAddress, flags); 792 } 793 794 dest.writeInt(mDnses.size()); 795 for(InetAddress d : mDnses) { 796 dest.writeByteArray(d.getAddress()); 797 } 798 dest.writeString(mDomains); 799 dest.writeInt(mMtu); 800 dest.writeInt(mRoutes.size()); 801 for(RouteInfo route : mRoutes) { 802 dest.writeParcelable(route, flags); 803 } 804 805 if (mHttpProxy != null) { 806 dest.writeByte((byte)1); 807 dest.writeParcelable(mHttpProxy, flags); 808 } else { 809 dest.writeByte((byte)0); 810 } 811 ArrayList<LinkProperties> stackedLinks = new ArrayList(mStackedLinks.values()); 812 dest.writeList(stackedLinks); 813 } 814 815 /** 816 * Implement the Parcelable interface. 817 */ 818 public static final Creator<LinkProperties> CREATOR = 819 new Creator<LinkProperties>() { 820 public LinkProperties createFromParcel(Parcel in) { 821 LinkProperties netProp = new LinkProperties(); 822 823 String iface = in.readString(); 824 if (iface != null) { 825 netProp.setInterfaceName(iface); 826 } 827 int addressCount = in.readInt(); 828 for (int i=0; i<addressCount; i++) { 829 netProp.addLinkAddress((LinkAddress)in.readParcelable(null)); 830 } 831 addressCount = in.readInt(); 832 for (int i=0; i<addressCount; i++) { 833 try { 834 netProp.addDns(InetAddress.getByAddress(in.createByteArray())); 835 } catch (UnknownHostException e) { } 836 } 837 netProp.setDomains(in.readString()); 838 netProp.setMtu(in.readInt()); 839 addressCount = in.readInt(); 840 for (int i=0; i<addressCount; i++) { 841 netProp.addRoute((RouteInfo)in.readParcelable(null)); 842 } 843 if (in.readByte() == 1) { 844 netProp.setHttpProxy((ProxyInfo)in.readParcelable(null)); 845 } 846 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>(); 847 in.readList(stackedLinks, LinkProperties.class.getClassLoader()); 848 for (LinkProperties stackedLink: stackedLinks) { 849 netProp.addStackedLink(stackedLink); 850 } 851 return netProp; 852 } 853 854 public LinkProperties[] newArray(int size) { 855 return new LinkProperties[size]; 856 } 857 }; 858} 859