LinkProperties.java revision 8058f621891b41c6864b6004c1c47647436a0ac1
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.ProxyProperties; 20import android.os.Parcelable; 21import android.os.Parcel; 22import android.text.TextUtils; 23 24import java.net.InetAddress; 25import java.net.UnknownHostException; 26import java.util.ArrayList; 27import java.util.Collection; 28import java.util.Collections; 29 30/** 31 * Describes the properties of a network link. 32 * 33 * A link represents a connection to a network. 34 * It may have multiple addresses and multiple gateways, 35 * multiple dns servers but only one http proxy. 36 * 37 * Because it's a single network, the dns's 38 * are interchangeable and don't need associating with 39 * particular addresses. The gateways similarly don't 40 * need associating with particular addresses. 41 * 42 * A dual stack interface works fine in this model: 43 * each address has it's own prefix length to describe 44 * the local network. The dns servers all return 45 * both v4 addresses and v6 addresses regardless of the 46 * address family of the server itself (rfc4213) and we 47 * don't care which is used. The gateways will be 48 * selected based on the destination address and the 49 * source address has no relavence. 50 * @hide 51 */ 52public class LinkProperties implements Parcelable { 53 54 private String mIfaceName; 55 private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>(); 56 private Collection<InetAddress> mDnses = new ArrayList<InetAddress>(); 57 private String mDomains; 58 private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 59 private ProxyProperties mHttpProxy; 60 61 public static class CompareResult<T> { 62 public Collection<T> removed = new ArrayList<T>(); 63 public Collection<T> added = new ArrayList<T>(); 64 65 @Override 66 public String toString() { 67 String retVal = "removed=["; 68 for (T addr : removed) retVal += addr.toString() + ","; 69 retVal += "] added=["; 70 for (T addr : added) retVal += addr.toString() + ","; 71 retVal += "]"; 72 return retVal; 73 } 74 } 75 76 public LinkProperties() { 77 clear(); 78 } 79 80 // copy constructor instead of clone 81 public LinkProperties(LinkProperties source) { 82 if (source != null) { 83 mIfaceName = source.getInterfaceName(); 84 for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l); 85 for (InetAddress i : source.getDnses()) mDnses.add(i); 86 mDomains = source.getDomains(); 87 for (RouteInfo r : source.getRoutes()) mRoutes.add(r); 88 mHttpProxy = (source.getHttpProxy() == null) ? 89 null : new ProxyProperties(source.getHttpProxy()); 90 } 91 } 92 93 public void setInterfaceName(String iface) { 94 mIfaceName = iface; 95 } 96 97 public String getInterfaceName() { 98 return mIfaceName; 99 } 100 101 public Collection<InetAddress> getAddresses() { 102 Collection<InetAddress> addresses = new ArrayList<InetAddress>(); 103 for (LinkAddress linkAddress : mLinkAddresses) { 104 addresses.add(linkAddress.getAddress()); 105 } 106 return Collections.unmodifiableCollection(addresses); 107 } 108 109 public void addLinkAddress(LinkAddress address) { 110 if (address != null) mLinkAddresses.add(address); 111 } 112 113 public Collection<LinkAddress> getLinkAddresses() { 114 return Collections.unmodifiableCollection(mLinkAddresses); 115 } 116 117 public void addDns(InetAddress dns) { 118 if (dns != null) mDnses.add(dns); 119 } 120 121 public Collection<InetAddress> getDnses() { 122 return Collections.unmodifiableCollection(mDnses); 123 } 124 125 public String getDomains() { 126 return mDomains; 127 } 128 129 public void setDomains(String domains) { 130 mDomains = domains; 131 } 132 133 public void addRoute(RouteInfo route) { 134 if (route != null) mRoutes.add(route); 135 } 136 public Collection<RouteInfo> getRoutes() { 137 return Collections.unmodifiableCollection(mRoutes); 138 } 139 140 public void setHttpProxy(ProxyProperties proxy) { 141 mHttpProxy = proxy; 142 } 143 public ProxyProperties getHttpProxy() { 144 return mHttpProxy; 145 } 146 147 public void clear() { 148 mIfaceName = null; 149 mLinkAddresses.clear(); 150 mDnses.clear(); 151 mDomains = null; 152 mRoutes.clear(); 153 mHttpProxy = null; 154 } 155 156 /** 157 * Implement the Parcelable interface 158 * @hide 159 */ 160 public int describeContents() { 161 return 0; 162 } 163 164 @Override 165 public String toString() { 166 String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " "); 167 168 String linkAddresses = "LinkAddresses: ["; 169 for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ","; 170 linkAddresses += "] "; 171 172 String dns = "DnsAddresses: ["; 173 for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ","; 174 dns += "] "; 175 176 String domainName = "Domains: " + mDomains; 177 178 String routes = " Routes: ["; 179 for (RouteInfo route : mRoutes) routes += route.toString() + ","; 180 routes += "] "; 181 String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " "); 182 183 return ifaceName + linkAddresses + routes + dns + domainName + proxy; 184 } 185 186 /** 187 * Compares this {@code LinkProperties} interface name against the target 188 * 189 * @param target LinkProperties to compare. 190 * @return {@code true} if both are identical, {@code false} otherwise. 191 */ 192 public boolean isIdenticalInterfaceName(LinkProperties target) { 193 return TextUtils.equals(getInterfaceName(), target.getInterfaceName()); 194 } 195 196 /** 197 * Compares this {@code LinkProperties} interface addresses against the target 198 * 199 * @param target LinkProperties to compare. 200 * @return {@code true} if both are identical, {@code false} otherwise. 201 */ 202 public boolean isIdenticalAddresses(LinkProperties target) { 203 Collection<InetAddress> targetAddresses = target.getAddresses(); 204 Collection<InetAddress> sourceAddresses = getAddresses(); 205 return (sourceAddresses.size() == targetAddresses.size()) ? 206 sourceAddresses.containsAll(targetAddresses) : false; 207 } 208 209 /** 210 * Compares this {@code LinkProperties} DNS addresses against the target 211 * 212 * @param target LinkProperties to compare. 213 * @return {@code true} if both are identical, {@code false} otherwise. 214 */ 215 public boolean isIdenticalDnses(LinkProperties target) { 216 Collection<InetAddress> targetDnses = target.getDnses(); 217 String targetDomains = target.getDomains(); 218 if (mDomains == null) { 219 if (targetDomains != null) return false; 220 } else { 221 if (mDomains.equals(targetDomains) == false) return false; 222 } 223 return (mDnses.size() == targetDnses.size()) ? 224 mDnses.containsAll(targetDnses) : false; 225 } 226 227 /** 228 * Compares this {@code LinkProperties} Routes against the target 229 * 230 * @param target LinkProperties to compare. 231 * @return {@code true} if both are identical, {@code false} otherwise. 232 */ 233 public boolean isIdenticalRoutes(LinkProperties target) { 234 Collection<RouteInfo> targetRoutes = target.getRoutes(); 235 return (mRoutes.size() == targetRoutes.size()) ? 236 mRoutes.containsAll(targetRoutes) : false; 237 } 238 239 /** 240 * Compares this {@code LinkProperties} HttpProxy against the target 241 * 242 * @param target LinkProperties to compare. 243 * @return {@code true} if both are identical, {@code false} otherwise. 244 */ 245 public boolean isIdenticalHttpProxy(LinkProperties target) { 246 return getHttpProxy() == null ? target.getHttpProxy() == null : 247 getHttpProxy().equals(target.getHttpProxy()); 248 } 249 250 @Override 251 /** 252 * Compares this {@code LinkProperties} instance against the target 253 * LinkProperties in {@code obj}. Two LinkPropertieses are equal if 254 * all their fields are equal in values. 255 * 256 * For collection fields, such as mDnses, containsAll() is used to check 257 * if two collections contains the same elements, independent of order. 258 * There are two thoughts regarding containsAll() 259 * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal. 260 * 2. Worst case performance is O(n^2). 261 * 262 * @param obj the object to be tested for equality. 263 * @return {@code true} if both objects are equal, {@code false} otherwise. 264 */ 265 public boolean equals(Object obj) { 266 if (this == obj) return true; 267 268 if (!(obj instanceof LinkProperties)) return false; 269 270 LinkProperties target = (LinkProperties) obj; 271 272 return isIdenticalInterfaceName(target) && 273 isIdenticalAddresses(target) && 274 isIdenticalDnses(target) && 275 isIdenticalRoutes(target) && 276 isIdenticalHttpProxy(target); 277 } 278 279 /** 280 * Return two lists, a list of addresses that would be removed from 281 * mLinkAddresses and a list of addresses that would be added to 282 * mLinkAddress which would then result in target and mLinkAddresses 283 * being the same list. 284 * 285 * @param target is a LinkProperties with the new list of addresses 286 * @return the removed and added lists. 287 */ 288 public CompareResult<LinkAddress> compareAddresses(LinkProperties target) { 289 /* 290 * Duplicate the LinkAddresses into removed, we will be removing 291 * address which are common between mLinkAddresses and target 292 * leaving the addresses that are different. And address which 293 * are in target but not in mLinkAddresses are placed in the 294 * addedAddresses. 295 */ 296 CompareResult<LinkAddress> result = new CompareResult<LinkAddress>(); 297 result.removed = new ArrayList<LinkAddress>(mLinkAddresses); 298 result.added.clear(); 299 if (target != null) { 300 for (LinkAddress newAddress : target.getLinkAddresses()) { 301 if (! result.removed.remove(newAddress)) { 302 result.added.add(newAddress); 303 } 304 } 305 } 306 return result; 307 } 308 309 /** 310 * Return two lists, a list of dns addresses that would be removed from 311 * mDnses and a list of addresses that would be added to 312 * mDnses which would then result in target and mDnses 313 * being the same list. 314 * 315 * @param target is a LinkProperties with the new list of dns addresses 316 * @return the removed and added lists. 317 */ 318 public CompareResult<InetAddress> compareDnses(LinkProperties target) { 319 /* 320 * Duplicate the InetAddresses into removed, we will be removing 321 * dns address which are common between mDnses and target 322 * leaving the addresses that are different. And dns address which 323 * are in target but not in mDnses are placed in the 324 * addedAddresses. 325 */ 326 CompareResult<InetAddress> result = new CompareResult<InetAddress>(); 327 328 result.removed = new ArrayList<InetAddress>(mDnses); 329 result.added.clear(); 330 if (target != null) { 331 for (InetAddress newAddress : target.getDnses()) { 332 if (! result.removed.remove(newAddress)) { 333 result.added.add(newAddress); 334 } 335 } 336 } 337 return result; 338 } 339 340 /** 341 * Return two lists, a list of routes that would be removed from 342 * mRoutes and a list of routes that would be added to 343 * mRoutes which would then result in target and mRoutes 344 * being the same list. 345 * 346 * @param target is a LinkProperties with the new list of routes 347 * @return the removed and added lists. 348 */ 349 public CompareResult<RouteInfo> compareRoutes(LinkProperties target) { 350 /* 351 * Duplicate the RouteInfos into removed, we will be removing 352 * routes which are common between mDnses and target 353 * leaving the routes that are different. And route address which 354 * are in target but not in mRoutes are placed in added. 355 */ 356 CompareResult<RouteInfo> result = new CompareResult<RouteInfo>(); 357 358 result.removed = new ArrayList<RouteInfo>(mRoutes); 359 result.added.clear(); 360 if (target != null) { 361 for (RouteInfo r : target.getRoutes()) { 362 if (! result.removed.remove(r)) { 363 result.added.add(r); 364 } 365 } 366 } 367 return result; 368 } 369 370 371 @Override 372 /** 373 * generate hashcode based on significant fields 374 * Equal objects must produce the same hash code, while unequal objects 375 * may have the same hash codes. 376 */ 377 public int hashCode() { 378 return ((null == mIfaceName) ? 0 : mIfaceName.hashCode() 379 + mLinkAddresses.size() * 31 380 + mDnses.size() * 37 381 + ((null == mDomains) ? 0 : mDomains.hashCode()) 382 + mRoutes.size() * 41 383 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())); 384 } 385 386 /** 387 * Implement the Parcelable interface. 388 */ 389 public void writeToParcel(Parcel dest, int flags) { 390 dest.writeString(getInterfaceName()); 391 dest.writeInt(mLinkAddresses.size()); 392 for(LinkAddress linkAddress : mLinkAddresses) { 393 dest.writeParcelable(linkAddress, flags); 394 } 395 396 dest.writeInt(mDnses.size()); 397 for(InetAddress d : mDnses) { 398 dest.writeByteArray(d.getAddress()); 399 } 400 dest.writeString(mDomains); 401 402 dest.writeInt(mRoutes.size()); 403 for(RouteInfo route : mRoutes) { 404 dest.writeParcelable(route, flags); 405 } 406 407 if (mHttpProxy != null) { 408 dest.writeByte((byte)1); 409 dest.writeParcelable(mHttpProxy, flags); 410 } else { 411 dest.writeByte((byte)0); 412 } 413 } 414 415 /** 416 * Implement the Parcelable interface. 417 */ 418 public static final Creator<LinkProperties> CREATOR = 419 new Creator<LinkProperties>() { 420 public LinkProperties createFromParcel(Parcel in) { 421 LinkProperties netProp = new LinkProperties(); 422 423 String iface = in.readString(); 424 if (iface != null) { 425 netProp.setInterfaceName(iface); 426 } 427 int addressCount = in.readInt(); 428 for (int i=0; i<addressCount; i++) { 429 netProp.addLinkAddress((LinkAddress)in.readParcelable(null)); 430 } 431 addressCount = in.readInt(); 432 for (int i=0; i<addressCount; i++) { 433 try { 434 netProp.addDns(InetAddress.getByAddress(in.createByteArray())); 435 } catch (UnknownHostException e) { } 436 } 437 netProp.setDomains(in.readString()); 438 addressCount = in.readInt(); 439 for (int i=0; i<addressCount; i++) { 440 netProp.addRoute((RouteInfo)in.readParcelable(null)); 441 } 442 if (in.readByte() == 1) { 443 netProp.setHttpProxy((ProxyProperties)in.readParcelable(null)); 444 } 445 return netProp; 446 } 447 448 public LinkProperties[] newArray(int size) { 449 return new LinkProperties[size]; 450 } 451 }; 452} 453