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