content: /*
   * Copyright (C) 2011 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.net;
  
  import android.os.Parcel;
  import android.os.Parcelable;
  import com.klinker.android.logger.Log;
  
  import java.net.Inet4Address;
  import java.net.Inet6Address;
  import java.net.InetAddress;
  import java.net.UnknownHostException;
  import java.util.Collection;
  
  /**
   * A simple container for route information.
   *
   * @hide
   */
  public class RouteInfo implements Parcelable {
      private static final String TAG = "RouteInfo";
      /**
       * The IP destination address for this route.
       */
      private final LinkAddress mDestination;
  
      /**
       * The gateway address for this route.
       */
      private final InetAddress mGateway;
  
      private final boolean mIsDefault;
      private final boolean mIsHost;
  
      public RouteInfo(LinkAddress destination, InetAddress gateway) {
          if (destination == null) {
              if (gateway != null) {
                  if (gateway instanceof Inet4Address) {
                      try {
                          destination = new LinkAddress(Inet4Address.getLocalHost(), 0);
                      } catch (UnknownHostException e) {
                          // TODO Auto-generated catch block
                          Log.e(TAG, "exception thrown", e);
                      }
                  } else {
                      try {
                          destination = new LinkAddress(Inet6Address.getLocalHost(), 0);
                      } catch (UnknownHostException e) {
                          // TODO Auto-generated catch block
                          Log.e(TAG, "exception thrown", e);
                      }
                  }
              } else {
                  // no destination, no gateway. invalid.
                  throw new RuntimeException("Invalid arguments passed in.");
              }
          }
          if (gateway == null) {
              if (destination.getAddress() instanceof Inet4Address) {
                  try {
                      gateway = Inet4Address.getLocalHost();
                  } catch (UnknownHostException e) {
                      // TODO Auto-generated catch block
                      Log.e(TAG, "exception thrown", e);
                  }
              } else {
                  try {
                      gateway = Inet6Address.getLocalHost();
                  } catch (UnknownHostException e) {
                      // TODO Auto-generated catch block
                      Log.e(TAG, "exception thrown", e);
                  }
              }
          }
          mDestination = new LinkAddress(NetworkUtilsHelper.getNetworkPart(destination.getAddress(),
                  destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
          mGateway = gateway;
          mIsDefault = isDefault();
          mIsHost = isHost();
      }
  
      public RouteInfo(InetAddress gateway) {
          this(null, gateway);
      }
  
      public static RouteInfo makeHostRoute(InetAddress host) {
          return makeHostRoute(host, null);
      }
  
      public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway) {
          if (host == null) return null;
  
          if (host instanceof Inet4Address) {
              return new RouteInfo(new LinkAddress(host, 32), gateway);
          } else {
              return new RouteInfo(new LinkAddress(host, 128), gateway);
          }
      }
  
      private boolean isHost() {
          try {
              return (mGateway.equals(Inet4Address.getLocalHost()) || mGateway.equals(Inet6Address.getLocalHost()));
          } catch (UnknownHostException e) {
              // TODO Auto-generated catch block
              return false;
          }
      }
  
      private boolean isDefault() {
          boolean val = false;
          if (mGateway != null) {
              if (mGateway instanceof Inet4Address) {
                  val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
              } else {
                  val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
              }
          }
          return val;
      }
  
  
      public LinkAddress getDestination() {
          return mDestination;
      }
  
      public InetAddress getGateway() {
          return mGateway;
      }
  
      public boolean isDefaultRoute() {
          return mIsDefault;
      }
  
      public boolean isHostRoute() {
          return mIsHost;
      }
  
      public String toString() {
          String val = "";
          if (mDestination != null) val = mDestination.toString();
          if (mGateway != null) val += " -> " + mGateway.getHostAddress();
          return val;
      }
  
      public int describeContents() {
          return 0;
      }
  
      public void writeToParcel(Parcel dest, int flags) {
          if (mDestination == null) {
              dest.writeByte((byte) 0);
          } else {
              dest.writeByte((byte) 1);
              dest.writeByteArray(mDestination.getAddress().getAddress());
              dest.writeInt(mDestination.getNetworkPrefixLength());
          }
  
          if (mGateway == null) {
              dest.writeByte((byte) 0);
          } else {
              dest.writeByte((byte) 1);
              dest.writeByteArray(mGateway.getAddress());
          }
      }
  
      @Override
      public boolean equals(Object obj) {
          if (this == obj) return true;
  
          if (!(obj instanceof RouteInfo)) return false;
  
          RouteInfo target = (RouteInfo) obj;
  
          boolean sameDestination = (mDestination == null) ?
                  target.getDestination() == null
                  : mDestination.equals(target.getDestination());
  
          boolean sameAddress = (mGateway == null) ?
                  target.getGateway() == null
                  : mGateway.equals(target.getGateway());
  
          return sameDestination && sameAddress
                  && mIsDefault == target.mIsDefault;
      }
  
      @Override
      public int hashCode() {
          return (mDestination == null ? 0 : mDestination.hashCode())
                  + (mGateway == null ? 0 : mGateway.hashCode())
                  + (mIsDefault ? 3 : 7);
      }
  
      public static final Creator<RouteInfo> CREATOR =
              new Creator<RouteInfo>() {
                  public RouteInfo createFromParcel(Parcel in) {
                      InetAddress destAddr = null;
                      int prefix = 0;
                      InetAddress gateway = null;
  
                      if (in.readByte() == 1) {
                          byte[] addr = in.createByteArray();
                          prefix = in.readInt();
  
                          try {
                              destAddr = InetAddress.getByAddress(addr);
                          } catch (UnknownHostException e) {
                          }
                      }
  
                      if (in.readByte() == 1) {
                          byte[] addr = in.createByteArray();
  
                          try {
                              gateway = InetAddress.getByAddress(addr);
                          } catch (UnknownHostException e) {
                          }
                      }
  
                      LinkAddress dest = null;
  
                      if (destAddr != null) {
                          dest = new LinkAddress(destAddr, prefix);
                      }
  
                      return new RouteInfo(dest, gateway);
                  }
  
                  public RouteInfo[] newArray(int size) {
                      return new RouteInfo[size];
                  }
              };
  
      private boolean matches(InetAddress destination) {
          if (destination == null) return false;
  
          // if the destination is present and the route is default.
          // return true
          if (isDefault()) return true;
  
          // match the route destination and destination with prefix length
          InetAddress dstNet = NetworkUtilsHelper.getNetworkPart(destination,
                  mDestination.getNetworkPrefixLength());
  
          return mDestination.getAddress().equals(dstNet);
      }
  
      /**
       * Find the route from a Collection of routes that best matches a given address.
       * May return null if no routes are applicable.
       *
       * @param routes a Collection of RouteInfos to chose from
       * @param dest   the InetAddress your trying to get to
       * @return the RouteInfo from the Collection that best fits the given address
       */
      public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
          if ((routes == null) || (dest == null)) return null;
  
          RouteInfo bestRoute = null;
          // pick a longest prefix match under same address type
          for (RouteInfo route : routes) {
              if (NetworkUtilsHelper.addressTypeMatches(route.mDestination.getAddress(), dest)) {
                  if ((bestRoute != null) &&
                          (bestRoute.mDestination.getNetworkPrefixLength() >=
                                  route.mDestination.getNetworkPrefixLength())) {
                      continue;
                  }
                  if (route.matches(dest)) bestRoute = route;
              }
          }
          return bestRoute;
      }
  }
  