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 * @hide 33 */ 34public class RouteInfo implements Parcelable { 35 /** 36 * The IP destination address for this route. 37 */ 38 private final LinkAddress mDestination; 39 40 /** 41 * The gateway address for this route. 42 */ 43 private final InetAddress mGateway; 44 45 private final boolean mIsDefault; 46 private final boolean mIsHost; 47 48 public RouteInfo(LinkAddress destination, InetAddress gateway) { 49 if (destination == null) { 50 if (gateway != null) { 51 if (gateway instanceof Inet4Address) { 52 destination = new LinkAddress(Inet4Address.ANY, 0); 53 } else { 54 destination = new LinkAddress(Inet6Address.ANY, 0); 55 } 56 } else { 57 // no destination, no gateway. invalid. 58 throw new RuntimeException("Invalid arguments passed in."); 59 } 60 } 61 if (gateway == null) { 62 if (destination.getAddress() instanceof Inet4Address) { 63 gateway = Inet4Address.ANY; 64 } else { 65 gateway = Inet6Address.ANY; 66 } 67 } 68 mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(), 69 destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength()); 70 mGateway = gateway; 71 mIsDefault = isDefault(); 72 mIsHost = isHost(); 73 } 74 75 public RouteInfo(InetAddress gateway) { 76 this(null, gateway); 77 } 78 79 public static RouteInfo makeHostRoute(InetAddress host) { 80 return makeHostRoute(host, null); 81 } 82 83 public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway) { 84 if (host == null) return null; 85 86 if (host instanceof Inet4Address) { 87 return new RouteInfo(new LinkAddress(host, 32), gateway); 88 } else { 89 return new RouteInfo(new LinkAddress(host, 128), gateway); 90 } 91 } 92 93 private boolean isHost() { 94 return (mGateway.equals(Inet4Address.ANY) || mGateway.equals(Inet6Address.ANY)); 95 } 96 97 private boolean isDefault() { 98 boolean val = false; 99 if (mGateway != null) { 100 if (mGateway instanceof Inet4Address) { 101 val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0); 102 } else { 103 val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0); 104 } 105 } 106 return val; 107 } 108 109 110 public LinkAddress getDestination() { 111 return mDestination; 112 } 113 114 public InetAddress getGateway() { 115 return mGateway; 116 } 117 118 public boolean isDefaultRoute() { 119 return mIsDefault; 120 } 121 122 public boolean isHostRoute() { 123 return mIsHost; 124 } 125 126 public String toString() { 127 String val = ""; 128 if (mDestination != null) val = mDestination.toString(); 129 if (mGateway != null) val += " -> " + mGateway.getHostAddress(); 130 return val; 131 } 132 133 public int describeContents() { 134 return 0; 135 } 136 137 public void writeToParcel(Parcel dest, int flags) { 138 if (mDestination == null) { 139 dest.writeByte((byte) 0); 140 } else { 141 dest.writeByte((byte) 1); 142 dest.writeByteArray(mDestination.getAddress().getAddress()); 143 dest.writeInt(mDestination.getNetworkPrefixLength()); 144 } 145 146 if (mGateway == null) { 147 dest.writeByte((byte) 0); 148 } else { 149 dest.writeByte((byte) 1); 150 dest.writeByteArray(mGateway.getAddress()); 151 } 152 } 153 154 @Override 155 public boolean equals(Object obj) { 156 if (this == obj) return true; 157 158 if (!(obj instanceof RouteInfo)) return false; 159 160 RouteInfo target = (RouteInfo) obj; 161 162 boolean sameDestination = ( mDestination == null) ? 163 target.getDestination() == null 164 : mDestination.equals(target.getDestination()); 165 166 boolean sameAddress = (mGateway == null) ? 167 target.getGateway() == null 168 : mGateway.equals(target.getGateway()); 169 170 return sameDestination && sameAddress 171 && mIsDefault == target.mIsDefault; 172 } 173 174 @Override 175 public int hashCode() { 176 return (mDestination == null ? 0 : mDestination.hashCode()) 177 + (mGateway == null ? 0 :mGateway.hashCode()) 178 + (mIsDefault ? 3 : 7); 179 } 180 181 public static final Creator<RouteInfo> CREATOR = 182 new Creator<RouteInfo>() { 183 public RouteInfo createFromParcel(Parcel in) { 184 InetAddress destAddr = null; 185 int prefix = 0; 186 InetAddress gateway = null; 187 188 if (in.readByte() == 1) { 189 byte[] addr = in.createByteArray(); 190 prefix = in.readInt(); 191 192 try { 193 destAddr = InetAddress.getByAddress(addr); 194 } catch (UnknownHostException e) {} 195 } 196 197 if (in.readByte() == 1) { 198 byte[] addr = in.createByteArray(); 199 200 try { 201 gateway = InetAddress.getByAddress(addr); 202 } catch (UnknownHostException e) {} 203 } 204 205 LinkAddress dest = null; 206 207 if (destAddr != null) { 208 dest = new LinkAddress(destAddr, prefix); 209 } 210 211 return new RouteInfo(dest, gateway); 212 } 213 214 public RouteInfo[] newArray(int size) { 215 return new RouteInfo[size]; 216 } 217 }; 218 219 private boolean matches(InetAddress destination) { 220 if (destination == null) return false; 221 222 // if the destination is present and the route is default. 223 // return true 224 if (isDefault()) return true; 225 226 // match the route destination and destination with prefix length 227 InetAddress dstNet = NetworkUtils.getNetworkPart(destination, 228 mDestination.getNetworkPrefixLength()); 229 230 return mDestination.getAddress().equals(dstNet); 231 } 232 233 /** 234 * Find the route from a Collection of routes that best matches a given address. 235 * May return null if no routes are applicable. 236 * @param routes a Collection of RouteInfos to chose from 237 * @param dest the InetAddress your trying to get to 238 * @return the RouteInfo from the Collection that best fits the given address 239 */ 240 public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) { 241 if ((routes == null) || (dest == null)) return null; 242 243 RouteInfo bestRoute = null; 244 // pick a longest prefix match under same address type 245 for (RouteInfo route : routes) { 246 if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) { 247 if ((bestRoute != null) && 248 (bestRoute.mDestination.getNetworkPrefixLength() >= 249 route.mDestination.getNetworkPrefixLength())) { 250 continue; 251 } 252 if (route.matches(dest)) bestRoute = route; 253 } 254 } 255 return bestRoute; 256 } 257} 258