RouteInfo.java revision 4095bd5a8811d4d8c2bb0efc28d9610629e27c89
1/* 2 * Copyright (C) 2011 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.os.Parcel; 20import android.os.Parcelable; 21 22import java.net.UnknownHostException; 23import java.net.InetAddress; 24import java.net.Inet4Address; 25import java.net.Inet6Address; 26 27import java.util.Collection; 28 29/** 30 * A simple container for route information. 31 * <p> 32 * This is used both to describe static network configuration and live network 33 * configuration information. In the static case the interface name (retrieved 34 * via {@link #getInterface}) should be {@code null} as that information will not 35 * yet be known. 36 * 37 * A route may be configured with: 38 * <ul> 39 * <li>a destination {@link LinkAddress} for directly-connected subnets, 40 * <li>a gateway {@link InetAddress} for default routes, 41 * <li>or both for a subnet. 42 * </ul> 43 */ 44public class RouteInfo implements Parcelable { 45 /** 46 * The IP destination address for this route. 47 */ 48 private final LinkAddress mDestination; 49 50 /** 51 * The gateway address for this route. 52 */ 53 private final InetAddress mGateway; 54 55 /** 56 * The interface for this route. 57 */ 58 private final String mInterface; 59 60 private final boolean mIsDefault; 61 private final boolean mIsHost; 62 private final boolean mHasGateway; 63 64 /** 65 * Constructs a RouteInfo object. 66 * 67 * If destination is null, then gateway must be specified and the 68 * constructed route is either the IPv4 default route <code>0.0.0.0</code> 69 * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default 70 * route <code>::/0</code> if gateway is an instance of 71 * {@link Inet6Address}. 72 * 73 * destination and gateway may not both be null. 74 * 75 * @param destination the destination prefix 76 * @param gateway the IP address to route packets through 77 * @param iface the interface name to send packets on 78 * 79 * @hide 80 */ 81 public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) { 82 if (destination == null) { 83 if (gateway != null) { 84 if (gateway instanceof Inet4Address) { 85 destination = new LinkAddress(Inet4Address.ANY, 0); 86 } else { 87 destination = new LinkAddress(Inet6Address.ANY, 0); 88 } 89 } else { 90 // no destination, no gateway. invalid. 91 throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," + 92 destination); 93 } 94 } 95 if (gateway == null) { 96 if (destination.getAddress() instanceof Inet4Address) { 97 gateway = Inet4Address.ANY; 98 } else { 99 gateway = Inet6Address.ANY; 100 } 101 } 102 mHasGateway = (!gateway.isAnyLocalAddress()); 103 104 mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(), 105 destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength()); 106 mGateway = gateway; 107 mInterface = iface; 108 mIsDefault = isDefault(); 109 mIsHost = isHost(); 110 } 111 112 /** 113 * Constructs a {@code RouteInfo} object. 114 * 115 * If destination is null, then gateway must be specified and the 116 * constructed route is either the IPv4 default route <code>0.0.0.0</code> 117 * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default 118 * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}. 119 * <p> 120 * Destination and gateway may not both be null. 121 * 122 * @param destination the destination address and prefix in a {@link LinkAddress} 123 * @param gateway the {@link InetAddress} to route packets through 124 */ 125 public RouteInfo(LinkAddress destination, InetAddress gateway) { 126 this(destination, gateway, null); 127 } 128 129 /** 130 * Constructs a default {@code RouteInfo} object. 131 * 132 * @param gateway the {@link InetAddress} to route packets through 133 */ 134 public RouteInfo(InetAddress gateway) { 135 this(null, gateway, null); 136 } 137 138 /** 139 * Constructs a {@code RouteInfo} object representing a direct connected subnet. 140 * 141 * @param host the {@link LinkAddress} describing the address and prefix length of the subnet. 142 */ 143 public RouteInfo(LinkAddress host) { 144 this(host, null, null); 145 } 146 147 /** 148 * @hide 149 */ 150 public static RouteInfo makeHostRoute(InetAddress host, String iface) { 151 return makeHostRoute(host, null, iface); 152 } 153 154 /** 155 * @hide 156 */ 157 public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway, String iface) { 158 if (host == null) return null; 159 160 if (host instanceof Inet4Address) { 161 return new RouteInfo(new LinkAddress(host, 32), gateway, iface); 162 } else { 163 return new RouteInfo(new LinkAddress(host, 128), gateway, iface); 164 } 165 } 166 167 private boolean isHost() { 168 return (mDestination.getAddress() instanceof Inet4Address && 169 mDestination.getNetworkPrefixLength() == 32) || 170 (mDestination.getAddress() instanceof Inet6Address && 171 mDestination.getNetworkPrefixLength() == 128); 172 } 173 174 private boolean isDefault() { 175 boolean val = false; 176 if (mGateway != null) { 177 if (mGateway instanceof Inet4Address) { 178 val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0); 179 } else { 180 val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0); 181 } 182 } 183 return val; 184 } 185 186 /** 187 * Retrieves the destination address and prefix length in the form of a {@link LinkAddress}. 188 * 189 * @return {@link LinkAddress} specifying the destination. 190 */ 191 public LinkAddress getDestination() { 192 return mDestination; 193 } 194 195 /** 196 * Retrieves the gateway or next hop {@link InetAddress} for this route. 197 * 198 * @return {@link InetAddress} specifying the gateway or next hop. 199 */ 200 public InetAddress getGateway() { 201 return mGateway; 202 } 203 204 /** 205 * Retrieves the interface used for this route, if known. Note that for static 206 * network configurations, this won't be set. 207 * 208 * @return The name of the interface used for this route. 209 */ 210 public String getInterface() { 211 return mInterface; 212 } 213 214 /** 215 * Indicates if this route is a default route (ie, has no destination specified). 216 * 217 * @return {@code true} if the destination is null or has a prefix length of 0. 218 */ 219 public boolean isDefaultRoute() { 220 return mIsDefault; 221 } 222 223 /** 224 * Indicates if this route is a host route (ie, matches only a single host address). 225 * 226 * @return {@code true} if the destination has a prefix length of 32/128 for v4/v6. 227 */ 228 public boolean isHostRoute() { 229 return mIsHost; 230 } 231 232 /** 233 * Indicates if this route has a next hop ({@code true}) or is directly-connected 234 * ({@code false}). 235 * 236 * @return {@code true} if a gateway is specified 237 */ 238 public boolean hasGateway() { 239 return mHasGateway; 240 } 241 242 /** 243 * @hide 244 */ 245 protected boolean matches(InetAddress destination) { 246 if (destination == null) return false; 247 248 // match the route destination and destination with prefix length 249 InetAddress dstNet = NetworkUtils.getNetworkPart(destination, 250 mDestination.getNetworkPrefixLength()); 251 252 return mDestination.getAddress().equals(dstNet); 253 } 254 255 /** 256 * Find the route from a Collection of routes that best matches a given address. 257 * May return null if no routes are applicable. 258 * @param routes a Collection of RouteInfos to chose from 259 * @param dest the InetAddress your trying to get to 260 * @return the RouteInfo from the Collection that best fits the given address 261 * 262 * @hide 263 */ 264 public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) { 265 if ((routes == null) || (dest == null)) return null; 266 267 RouteInfo bestRoute = null; 268 // pick a longest prefix match under same address type 269 for (RouteInfo route : routes) { 270 if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) { 271 if ((bestRoute != null) && 272 (bestRoute.mDestination.getNetworkPrefixLength() >= 273 route.mDestination.getNetworkPrefixLength())) { 274 continue; 275 } 276 if (route.matches(dest)) bestRoute = route; 277 } 278 } 279 return bestRoute; 280 } 281 282 public String toString() { 283 String val = ""; 284 if (mDestination != null) val = mDestination.toString(); 285 if (mGateway != null) val += " -> " + mGateway.getHostAddress(); 286 return val; 287 } 288 289 public boolean equals(Object obj) { 290 if (this == obj) return true; 291 292 if (!(obj instanceof RouteInfo)) return false; 293 294 RouteInfo target = (RouteInfo) obj; 295 296 boolean sameDestination = ( mDestination == null) ? 297 target.getDestination() == null 298 : mDestination.equals(target.getDestination()); 299 300 boolean sameAddress = (mGateway == null) ? 301 target.getGateway() == null 302 : mGateway.equals(target.getGateway()); 303 304 boolean sameInterface = (mInterface == null) ? 305 target.getInterface() == null 306 : mInterface.equals(target.getInterface()); 307 308 return sameDestination && sameAddress && sameInterface 309 && mIsDefault == target.mIsDefault; 310 } 311 312 public int hashCode() { 313 return (mDestination == null ? 0 : mDestination.hashCode() * 41) 314 + (mGateway == null ? 0 :mGateway.hashCode() * 47) 315 + (mInterface == null ? 0 :mInterface.hashCode() * 67) 316 + (mIsDefault ? 3 : 7); 317 } 318 319 /** 320 * Implement the Parcelable interface 321 * @hide 322 */ 323 public int describeContents() { 324 return 0; 325 } 326 327 /** 328 * Implement the Parcelable interface 329 * @hide 330 */ 331 public void writeToParcel(Parcel dest, int flags) { 332 if (mDestination == null) { 333 dest.writeByte((byte) 0); 334 } else { 335 dest.writeByte((byte) 1); 336 dest.writeByteArray(mDestination.getAddress().getAddress()); 337 dest.writeInt(mDestination.getNetworkPrefixLength()); 338 } 339 340 if (mGateway == null) { 341 dest.writeByte((byte) 0); 342 } else { 343 dest.writeByte((byte) 1); 344 dest.writeByteArray(mGateway.getAddress()); 345 } 346 347 dest.writeString(mInterface); 348 } 349 350 /** 351 * Implement the Parcelable interface. 352 * @hide 353 */ 354 public static final Creator<RouteInfo> CREATOR = 355 new Creator<RouteInfo>() { 356 public RouteInfo createFromParcel(Parcel in) { 357 InetAddress destAddr = null; 358 int prefix = 0; 359 InetAddress gateway = null; 360 361 if (in.readByte() == 1) { 362 byte[] addr = in.createByteArray(); 363 prefix = in.readInt(); 364 365 try { 366 destAddr = InetAddress.getByAddress(addr); 367 } catch (UnknownHostException e) {} 368 } 369 370 if (in.readByte() == 1) { 371 byte[] addr = in.createByteArray(); 372 373 try { 374 gateway = InetAddress.getByAddress(addr); 375 } catch (UnknownHostException e) {} 376 } 377 378 String iface = in.readString(); 379 380 LinkAddress dest = null; 381 382 if (destAddr != null) { 383 dest = new LinkAddress(destAddr, prefix); 384 } 385 386 return new RouteInfo(dest, gateway, iface); 387 } 388 389 public RouteInfo[] newArray(int size) { 390 return new RouteInfo[size]; 391 } 392 }; 393} 394