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