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