RouteInfo.java revision 574b00a3621d1e6db560ea2f4593a0ae7a90e145
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 * 32 * In order to be used, a route must have a destination prefix and: 33 * 34 * - A gateway address (next-hop, for gatewayed routes), or 35 * - An interface (for directly-connected routes), or 36 * - Both a gateway and an interface. 37 * 38 * This class does not enforce these constraints because there is code that 39 * uses RouteInfo objects to store directly-connected routes without interfaces. 40 * Such objects cannot be used directly, but can be put into a LinkProperties 41 * object which then specifies the interface. 42 * 43 * @hide 44 */ 45public class RouteInfo implements Parcelable { 46 /** 47 * The IP destination address for this route. 48 */ 49 private final LinkAddress mDestination; 50 51 /** 52 * The gateway address for this route. 53 */ 54 private final InetAddress mGateway; 55 56 /** 57 * The interface for this route. 58 */ 59 private final String mInterface; 60 61 private final boolean mIsDefault; 62 private final boolean mIsHost; 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 @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 public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) { 80 if (destination == null) { 81 if (gateway != null) { 82 if (gateway instanceof Inet4Address) { 83 destination = new LinkAddress(Inet4Address.ANY, 0); 84 } else { 85 destination = new LinkAddress(Inet6Address.ANY, 0); 86 } 87 } else { 88 // no destination, no gateway. invalid. 89 throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," + 90 destination); 91 } 92 } 93 if (gateway == null) { 94 if (destination.getAddress() instanceof Inet4Address) { 95 gateway = Inet4Address.ANY; 96 } else { 97 gateway = Inet6Address.ANY; 98 } 99 } 100 mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(), 101 destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength()); 102 mGateway = gateway; 103 mInterface = iface; 104 mIsDefault = isDefault(); 105 mIsHost = isHost(); 106 } 107 108 public RouteInfo(LinkAddress destination, InetAddress gateway) { 109 this(destination, gateway, null); 110 } 111 112 public RouteInfo(InetAddress gateway) { 113 this(null, gateway, null); 114 } 115 116 public RouteInfo(LinkAddress host) { 117 this(host, null, null); 118 } 119 120 public static RouteInfo makeHostRoute(InetAddress host, String iface) { 121 return makeHostRoute(host, null, iface); 122 } 123 124 public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway, String iface) { 125 if (host == null) return null; 126 127 if (host instanceof Inet4Address) { 128 return new RouteInfo(new LinkAddress(host, 32), gateway, iface); 129 } else { 130 return new RouteInfo(new LinkAddress(host, 128), gateway, iface); 131 } 132 } 133 134 private boolean isHost() { 135 return (mGateway.equals(Inet4Address.ANY) || mGateway.equals(Inet6Address.ANY)); 136 } 137 138 private boolean isDefault() { 139 boolean val = false; 140 if (mGateway != null) { 141 if (mGateway instanceof Inet4Address) { 142 val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0); 143 } else { 144 val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0); 145 } 146 } 147 return val; 148 } 149 150 151 public LinkAddress getDestination() { 152 return mDestination; 153 } 154 155 public InetAddress getGateway() { 156 return mGateway; 157 } 158 159 public String getInterface() { 160 return mInterface; 161 } 162 163 public boolean isDefaultRoute() { 164 return mIsDefault; 165 } 166 167 public boolean isHostRoute() { 168 return mIsHost; 169 } 170 171 public String toString() { 172 String val = ""; 173 if (mDestination != null) val = mDestination.toString(); 174 if (mGateway != null) val += " -> " + mGateway.getHostAddress(); 175 return val; 176 } 177 178 public int describeContents() { 179 return 0; 180 } 181 182 public void writeToParcel(Parcel dest, int flags) { 183 if (mDestination == null) { 184 dest.writeByte((byte) 0); 185 } else { 186 dest.writeByte((byte) 1); 187 dest.writeByteArray(mDestination.getAddress().getAddress()); 188 dest.writeInt(mDestination.getNetworkPrefixLength()); 189 } 190 191 if (mGateway == null) { 192 dest.writeByte((byte) 0); 193 } else { 194 dest.writeByte((byte) 1); 195 dest.writeByteArray(mGateway.getAddress()); 196 } 197 198 dest.writeString(mInterface); 199 } 200 201 @Override 202 public boolean equals(Object obj) { 203 if (this == obj) return true; 204 205 if (!(obj instanceof RouteInfo)) return false; 206 207 RouteInfo target = (RouteInfo) obj; 208 209 boolean sameDestination = ( mDestination == null) ? 210 target.getDestination() == null 211 : mDestination.equals(target.getDestination()); 212 213 boolean sameAddress = (mGateway == null) ? 214 target.getGateway() == null 215 : mGateway.equals(target.getGateway()); 216 217 boolean sameInterface = (mInterface == null) ? 218 target.getInterface() == null 219 : mInterface.equals(target.getInterface()); 220 221 return sameDestination && sameAddress && sameInterface 222 && mIsDefault == target.mIsDefault; 223 } 224 225 @Override 226 public int hashCode() { 227 return (mDestination == null ? 0 : mDestination.hashCode() * 41) 228 + (mGateway == null ? 0 :mGateway.hashCode() * 47) 229 + (mInterface == null ? 0 :mInterface.hashCode() * 67) 230 + (mIsDefault ? 3 : 7); 231 } 232 233 public static final Creator<RouteInfo> CREATOR = 234 new Creator<RouteInfo>() { 235 public RouteInfo createFromParcel(Parcel in) { 236 InetAddress destAddr = null; 237 int prefix = 0; 238 InetAddress gateway = null; 239 240 if (in.readByte() == 1) { 241 byte[] addr = in.createByteArray(); 242 prefix = in.readInt(); 243 244 try { 245 destAddr = InetAddress.getByAddress(addr); 246 } catch (UnknownHostException e) {} 247 } 248 249 if (in.readByte() == 1) { 250 byte[] addr = in.createByteArray(); 251 252 try { 253 gateway = InetAddress.getByAddress(addr); 254 } catch (UnknownHostException e) {} 255 } 256 257 String iface = in.readString(); 258 259 LinkAddress dest = null; 260 261 if (destAddr != null) { 262 dest = new LinkAddress(destAddr, prefix); 263 } 264 265 return new RouteInfo(dest, gateway, iface); 266 } 267 268 public RouteInfo[] newArray(int size) { 269 return new RouteInfo[size]; 270 } 271 }; 272 273 protected boolean matches(InetAddress destination) { 274 if (destination == null) return false; 275 276 // match the route destination and destination with prefix length 277 InetAddress dstNet = NetworkUtils.getNetworkPart(destination, 278 mDestination.getNetworkPrefixLength()); 279 280 return mDestination.getAddress().equals(dstNet); 281 } 282 283 /** 284 * Find the route from a Collection of routes that best matches a given address. 285 * May return null if no routes are applicable. 286 * @param routes a Collection of RouteInfos to chose from 287 * @param dest the InetAddress your trying to get to 288 * @return the RouteInfo from the Collection that best fits the given address 289 */ 290 public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) { 291 if ((routes == null) || (dest == null)) return null; 292 293 RouteInfo bestRoute = null; 294 // pick a longest prefix match under same address type 295 for (RouteInfo route : routes) { 296 if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) { 297 if ((bestRoute != null) && 298 (bestRoute.mDestination.getNetworkPrefixLength() >= 299 route.mDestination.getNetworkPrefixLength())) { 300 continue; 301 } 302 if (route.matches(dest)) bestRoute = route; 303 } 304 } 305 return bestRoute; 306 } 307} 308