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.Inet4Address;
     26 import java.net.Inet6Address;
     27 
     28 import java.net.UnknownHostException;
     29 import java.util.ArrayList;
     30 import java.util.Collection;
     31 import java.util.Collections;
     32 import java.util.Hashtable;
     33 
     34 /**
     35  * Describes the properties of a network link.
     36  *
     37  * A link represents a connection to a network.
     38  * It may have multiple addresses and multiple gateways,
     39  * multiple dns servers but only one http proxy.
     40  *
     41  * Because it's a single network, the dns's
     42  * are interchangeable and don't need associating with
     43  * particular addresses.  The gateways similarly don't
     44  * need associating with particular addresses.
     45  *
     46  * A dual stack interface works fine in this model:
     47  * each address has it's own prefix length to describe
     48  * the local network.  The dns servers all return
     49  * both v4 addresses and v6 addresses regardless of the
     50  * address family of the server itself (rfc4213) and we
     51  * don't care which is used.  The gateways will be
     52  * selected based on the destination address and the
     53  * source address has no relavence.
     54  *
     55  * Links can also be stacked on top of each other.
     56  * This can be used, for example, to represent a tunnel
     57  * interface that runs on top of a physical interface.
     58  *
     59  * @hide
     60  */
     61 public class LinkProperties implements Parcelable {
     62     // The interface described by the network link.
     63     private String mIfaceName;
     64     private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
     65     private Collection<InetAddress> mDnses = new ArrayList<InetAddress>();
     66     private String mDomains;
     67     private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
     68     private ProxyProperties mHttpProxy;
     69     private int mMtu;
     70 
     71     // Stores the properties of links that are "stacked" above this link.
     72     // Indexed by interface name to allow modification and to prevent duplicates being added.
     73     private Hashtable<String, LinkProperties> mStackedLinks =
     74         new Hashtable<String, LinkProperties>();
     75 
     76     public static class CompareResult<T> {
     77         public Collection<T> removed = new ArrayList<T>();
     78         public Collection<T> added = new ArrayList<T>();
     79 
     80         @Override
     81         public String toString() {
     82             String retVal = "removed=[";
     83             for (T addr : removed) retVal += addr.toString() + ",";
     84             retVal += "] added=[";
     85             for (T addr : added) retVal += addr.toString() + ",";
     86             retVal += "]";
     87             return retVal;
     88         }
     89     }
     90 
     91     public LinkProperties() {
     92         clear();
     93     }
     94 
     95     // copy constructor instead of clone
     96     public LinkProperties(LinkProperties source) {
     97         if (source != null) {
     98             mIfaceName = source.getInterfaceName();
     99             for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l);
    100             for (InetAddress i : source.getDnses()) mDnses.add(i);
    101             mDomains = source.getDomains();
    102             for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
    103             mHttpProxy = (source.getHttpProxy() == null)  ?
    104                     null : new ProxyProperties(source.getHttpProxy());
    105             for (LinkProperties l: source.mStackedLinks.values()) {
    106                 addStackedLink(l);
    107             }
    108             setMtu(source.getMtu());
    109         }
    110     }
    111 
    112     public void setInterfaceName(String iface) {
    113         mIfaceName = iface;
    114         ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size());
    115         for (RouteInfo route : mRoutes) {
    116             newRoutes.add(routeWithInterface(route));
    117         }
    118         mRoutes = newRoutes;
    119     }
    120 
    121     public String getInterfaceName() {
    122         return mIfaceName;
    123     }
    124 
    125     public Collection<String> getAllInterfaceNames() {
    126         Collection interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1);
    127         if (mIfaceName != null) interfaceNames.add(new String(mIfaceName));
    128         for (LinkProperties stacked: mStackedLinks.values()) {
    129             interfaceNames.addAll(stacked.getAllInterfaceNames());
    130         }
    131         return interfaceNames;
    132     }
    133 
    134     /**
    135      * Returns all the addresses on this link.
    136      */
    137     public Collection<InetAddress> getAddresses() {
    138         Collection<InetAddress> addresses = new ArrayList<InetAddress>();
    139         for (LinkAddress linkAddress : mLinkAddresses) {
    140             addresses.add(linkAddress.getAddress());
    141         }
    142         return Collections.unmodifiableCollection(addresses);
    143     }
    144 
    145     /**
    146      * Returns all the addresses on this link and all the links stacked above it.
    147      */
    148     public Collection<InetAddress> getAllAddresses() {
    149         Collection<InetAddress> addresses = new ArrayList<InetAddress>();
    150         for (LinkAddress linkAddress : mLinkAddresses) {
    151             addresses.add(linkAddress.getAddress());
    152         }
    153         for (LinkProperties stacked: mStackedLinks.values()) {
    154             addresses.addAll(stacked.getAllAddresses());
    155         }
    156         return addresses;
    157     }
    158 
    159     /**
    160      * Adds a link address if it does not exist, or update it if it does.
    161      * @param address The {@code LinkAddress} to add.
    162      * @return true if the address was added, false if it already existed.
    163      */
    164     public boolean addLinkAddress(LinkAddress address) {
    165         // TODO: when the LinkAddress has other attributes beyond the
    166         // address and the prefix length, update them here.
    167         if (address != null && !mLinkAddresses.contains(address)) {
    168             mLinkAddresses.add(address);
    169             return true;
    170         }
    171         return false;
    172     }
    173 
    174     /**
    175      * Removes a link address.
    176      * @param address The {@code LinkAddress} to remove.
    177      * @return true if the address was removed, false if it did not exist.
    178      */
    179     public boolean removeLinkAddress(LinkAddress toRemove) {
    180         return mLinkAddresses.remove(toRemove);
    181     }
    182 
    183     /**
    184      * Returns all the addresses on this link.
    185      */
    186     public Collection<LinkAddress> getLinkAddresses() {
    187         return Collections.unmodifiableCollection(mLinkAddresses);
    188     }
    189 
    190     /**
    191      * Returns all the addresses on this link and all the links stacked above it.
    192      */
    193     public Collection<LinkAddress> getAllLinkAddresses() {
    194         Collection<LinkAddress> addresses = new ArrayList<LinkAddress>();
    195         addresses.addAll(mLinkAddresses);
    196         for (LinkProperties stacked: mStackedLinks.values()) {
    197             addresses.addAll(stacked.getAllLinkAddresses());
    198         }
    199         return addresses;
    200     }
    201 
    202     /**
    203      * Replaces the LinkAddresses on this link with the given collection of addresses.
    204      */
    205     public void setLinkAddresses(Collection<LinkAddress> addresses) {
    206         mLinkAddresses.clear();
    207         for (LinkAddress address: addresses) {
    208             addLinkAddress(address);
    209         }
    210     }
    211 
    212     public void addDns(InetAddress dns) {
    213         if (dns != null) mDnses.add(dns);
    214     }
    215 
    216     public Collection<InetAddress> getDnses() {
    217         return Collections.unmodifiableCollection(mDnses);
    218     }
    219 
    220     public String getDomains() {
    221         return mDomains;
    222     }
    223 
    224     public void setDomains(String domains) {
    225         mDomains = domains;
    226     }
    227 
    228     public void setMtu(int mtu) {
    229         mMtu = mtu;
    230     }
    231 
    232     public int getMtu() {
    233         return mMtu;
    234     }
    235 
    236     private RouteInfo routeWithInterface(RouteInfo route) {
    237         return new RouteInfo(
    238             route.getDestination(),
    239             route.getGateway(),
    240             mIfaceName);
    241     }
    242 
    243     public void addRoute(RouteInfo route) {
    244         if (route != null) {
    245             String routeIface = route.getInterface();
    246             if (routeIface != null && !routeIface.equals(mIfaceName)) {
    247                 throw new IllegalArgumentException(
    248                    "Route added with non-matching interface: " + routeIface +
    249                    " vs. " + mIfaceName);
    250             }
    251             mRoutes.add(routeWithInterface(route));
    252         }
    253     }
    254 
    255     /**
    256      * Returns all the routes on this link.
    257      */
    258     public Collection<RouteInfo> getRoutes() {
    259         return Collections.unmodifiableCollection(mRoutes);
    260     }
    261 
    262     /**
    263      * Returns all the routes on this link and all the links stacked above it.
    264      */
    265     public Collection<RouteInfo> getAllRoutes() {
    266         Collection<RouteInfo> routes = new ArrayList();
    267         routes.addAll(mRoutes);
    268         for (LinkProperties stacked: mStackedLinks.values()) {
    269             routes.addAll(stacked.getAllRoutes());
    270         }
    271         return routes;
    272     }
    273 
    274     public void setHttpProxy(ProxyProperties proxy) {
    275         mHttpProxy = proxy;
    276     }
    277     public ProxyProperties getHttpProxy() {
    278         return mHttpProxy;
    279     }
    280 
    281     /**
    282      * Adds a stacked link.
    283      *
    284      * If there is already a stacked link with the same interfacename as link,
    285      * that link is replaced with link. Otherwise, link is added to the list
    286      * of stacked links. If link is null, nothing changes.
    287      *
    288      * @param link The link to add.
    289      * @return true if the link was stacked, false otherwise.
    290      */
    291     public boolean addStackedLink(LinkProperties link) {
    292         if (link != null && link.getInterfaceName() != null) {
    293             mStackedLinks.put(link.getInterfaceName(), link);
    294             return true;
    295         }
    296         return false;
    297     }
    298 
    299     /**
    300      * Removes a stacked link.
    301      *
    302      * If there a stacked link with the same interfacename as link, it is
    303      * removed. Otherwise, nothing changes.
    304      *
    305      * @param link The link to remove.
    306      * @return true if the link was removed, false otherwise.
    307      */
    308     public boolean removeStackedLink(LinkProperties link) {
    309         if (link != null && link.getInterfaceName() != null) {
    310             LinkProperties removed = mStackedLinks.remove(link.getInterfaceName());
    311             return removed != null;
    312         }
    313         return false;
    314     }
    315 
    316     /**
    317      * Returns all the links stacked on top of this link.
    318      */
    319     public Collection<LinkProperties> getStackedLinks() {
    320         Collection<LinkProperties> stacked = new ArrayList<LinkProperties>();
    321         for (LinkProperties link : mStackedLinks.values()) {
    322           stacked.add(new LinkProperties(link));
    323         }
    324         return Collections.unmodifiableCollection(stacked);
    325     }
    326 
    327     public void clear() {
    328         mIfaceName = null;
    329         mLinkAddresses.clear();
    330         mDnses.clear();
    331         mDomains = null;
    332         mRoutes.clear();
    333         mHttpProxy = null;
    334         mStackedLinks.clear();
    335         mMtu = 0;
    336     }
    337 
    338     /**
    339      * Implement the Parcelable interface
    340      * @hide
    341      */
    342     public int describeContents() {
    343         return 0;
    344     }
    345 
    346     @Override
    347     public String toString() {
    348         String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " ");
    349 
    350         String linkAddresses = "LinkAddresses: [";
    351         for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ",";
    352         linkAddresses += "] ";
    353 
    354         String dns = "DnsAddresses: [";
    355         for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ",";
    356         dns += "] ";
    357 
    358         String domainName = "Domains: " + mDomains;
    359 
    360         String mtu = "MTU: " + mMtu;
    361 
    362         String routes = " Routes: [";
    363         for (RouteInfo route : mRoutes) routes += route.toString() + ",";
    364         routes += "] ";
    365         String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
    366 
    367         String stacked = "";
    368         if (mStackedLinks.values().size() > 0) {
    369             stacked += " Stacked: [";
    370             for (LinkProperties link: mStackedLinks.values()) {
    371                 stacked += " [" + link.toString() + " ],";
    372             }
    373             stacked += "] ";
    374         }
    375         return "{" + ifaceName + linkAddresses + routes + dns + domainName + mtu
    376             + proxy + stacked + "}";
    377     }
    378 
    379     /**
    380      * Returns true if this link has an IPv4 address.
    381      *
    382      * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
    383      */
    384     public boolean hasIPv4Address() {
    385         for (LinkAddress address : mLinkAddresses) {
    386           if (address.getAddress() instanceof Inet4Address) {
    387             return true;
    388           }
    389         }
    390         return false;
    391     }
    392 
    393     /**
    394      * Returns true if this link has an IPv6 address.
    395      *
    396      * @return {@code true} if there is an IPv6 address, {@code false} otherwise.
    397      */
    398     public boolean hasIPv6Address() {
    399         for (LinkAddress address : mLinkAddresses) {
    400           if (address.getAddress() instanceof Inet6Address) {
    401             return true;
    402           }
    403         }
    404         return false;
    405     }
    406 
    407     /**
    408      * Compares this {@code LinkProperties} interface name against the target
    409      *
    410      * @param target LinkProperties to compare.
    411      * @return {@code true} if both are identical, {@code false} otherwise.
    412      */
    413     public boolean isIdenticalInterfaceName(LinkProperties target) {
    414         return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
    415     }
    416 
    417     /**
    418      * Compares this {@code LinkProperties} interface addresses against the target
    419      *
    420      * @param target LinkProperties to compare.
    421      * @return {@code true} if both are identical, {@code false} otherwise.
    422      */
    423     public boolean isIdenticalAddresses(LinkProperties target) {
    424         Collection<InetAddress> targetAddresses = target.getAddresses();
    425         Collection<InetAddress> sourceAddresses = getAddresses();
    426         return (sourceAddresses.size() == targetAddresses.size()) ?
    427                     sourceAddresses.containsAll(targetAddresses) : false;
    428     }
    429 
    430     /**
    431      * Compares this {@code LinkProperties} DNS addresses against the target
    432      *
    433      * @param target LinkProperties to compare.
    434      * @return {@code true} if both are identical, {@code false} otherwise.
    435      */
    436     public boolean isIdenticalDnses(LinkProperties target) {
    437         Collection<InetAddress> targetDnses = target.getDnses();
    438         String targetDomains = target.getDomains();
    439         if (mDomains == null) {
    440             if (targetDomains != null) return false;
    441         } else {
    442             if (mDomains.equals(targetDomains) == false) return false;
    443         }
    444         return (mDnses.size() == targetDnses.size()) ?
    445                     mDnses.containsAll(targetDnses) : false;
    446     }
    447 
    448     /**
    449      * Compares this {@code LinkProperties} Routes against the target
    450      *
    451      * @param target LinkProperties to compare.
    452      * @return {@code true} if both are identical, {@code false} otherwise.
    453      */
    454     public boolean isIdenticalRoutes(LinkProperties target) {
    455         Collection<RouteInfo> targetRoutes = target.getRoutes();
    456         return (mRoutes.size() == targetRoutes.size()) ?
    457                     mRoutes.containsAll(targetRoutes) : false;
    458     }
    459 
    460     /**
    461      * Compares this {@code LinkProperties} HttpProxy against the target
    462      *
    463      * @param target LinkProperties to compare.
    464      * @return {@code true} if both are identical, {@code false} otherwise.
    465      */
    466     public boolean isIdenticalHttpProxy(LinkProperties target) {
    467         return getHttpProxy() == null ? target.getHttpProxy() == null :
    468                     getHttpProxy().equals(target.getHttpProxy());
    469     }
    470 
    471     /**
    472      * Compares this {@code LinkProperties} stacked links against the target
    473      *
    474      * @param target LinkProperties to compare.
    475      * @return {@code true} if both are identical, {@code false} otherwise.
    476      */
    477     public boolean isIdenticalStackedLinks(LinkProperties target) {
    478         if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
    479             return false;
    480         }
    481         for (LinkProperties stacked : mStackedLinks.values()) {
    482             // Hashtable values can never be null.
    483             String iface = stacked.getInterfaceName();
    484             if (!stacked.equals(target.mStackedLinks.get(iface))) {
    485                 return false;
    486             }
    487         }
    488         return true;
    489     }
    490 
    491     /**
    492      * Compares this {@code LinkProperties} MTU against the target
    493      *
    494      * @param target LinkProperties to compare.
    495      * @return {@code true} if both are identical, {@code false} otherwise.
    496      */
    497     public boolean isIdenticalMtu(LinkProperties target) {
    498         return getMtu() == target.getMtu();
    499     }
    500 
    501     @Override
    502     /**
    503      * Compares this {@code LinkProperties} instance against the target
    504      * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
    505      * all their fields are equal in values.
    506      *
    507      * For collection fields, such as mDnses, containsAll() is used to check
    508      * if two collections contains the same elements, independent of order.
    509      * There are two thoughts regarding containsAll()
    510      * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
    511      * 2. Worst case performance is O(n^2).
    512      *
    513      * This method does not check that stacked interfaces are equal, because
    514      * stacked interfaces are not so much a property of the link as a
    515      * description of connections between links.
    516      *
    517      * @param obj the object to be tested for equality.
    518      * @return {@code true} if both objects are equal, {@code false} otherwise.
    519      */
    520     public boolean equals(Object obj) {
    521         if (this == obj) return true;
    522 
    523         if (!(obj instanceof LinkProperties)) return false;
    524 
    525         LinkProperties target = (LinkProperties) obj;
    526 
    527         return isIdenticalInterfaceName(target) &&
    528                 isIdenticalAddresses(target) &&
    529                 isIdenticalDnses(target) &&
    530                 isIdenticalRoutes(target) &&
    531                 isIdenticalHttpProxy(target) &&
    532                 isIdenticalStackedLinks(target) &&
    533                 isIdenticalMtu(target);
    534     }
    535 
    536     /**
    537      * Compares the addresses in this LinkProperties with another
    538      * LinkProperties, examining only addresses on the base link.
    539      *
    540      * @param target a LinkProperties with the new list of addresses
    541      * @return the differences between the addresses.
    542      */
    543     public CompareResult<LinkAddress> compareAddresses(LinkProperties target) {
    544         /*
    545          * Duplicate the LinkAddresses into removed, we will be removing
    546          * address which are common between mLinkAddresses and target
    547          * leaving the addresses that are different. And address which
    548          * are in target but not in mLinkAddresses are placed in the
    549          * addedAddresses.
    550          */
    551         CompareResult<LinkAddress> result = new CompareResult<LinkAddress>();
    552         result.removed = new ArrayList<LinkAddress>(mLinkAddresses);
    553         result.added.clear();
    554         if (target != null) {
    555             for (LinkAddress newAddress : target.getLinkAddresses()) {
    556                 if (! result.removed.remove(newAddress)) {
    557                     result.added.add(newAddress);
    558                 }
    559             }
    560         }
    561         return result;
    562     }
    563 
    564     /**
    565      * Compares the DNS addresses in this LinkProperties with another
    566      * LinkProperties, examining only DNS addresses on the base link.
    567      *
    568      * @param target a LinkProperties with the new list of dns addresses
    569      * @return the differences between the DNS addresses.
    570      */
    571     public CompareResult<InetAddress> compareDnses(LinkProperties target) {
    572         /*
    573          * Duplicate the InetAddresses into removed, we will be removing
    574          * dns address which are common between mDnses and target
    575          * leaving the addresses that are different. And dns address which
    576          * are in target but not in mDnses are placed in the
    577          * addedAddresses.
    578          */
    579         CompareResult<InetAddress> result = new CompareResult<InetAddress>();
    580 
    581         result.removed = new ArrayList<InetAddress>(mDnses);
    582         result.added.clear();
    583         if (target != null) {
    584             for (InetAddress newAddress : target.getDnses()) {
    585                 if (! result.removed.remove(newAddress)) {
    586                     result.added.add(newAddress);
    587                 }
    588             }
    589         }
    590         return result;
    591     }
    592 
    593     /**
    594      * Compares all routes in this LinkProperties with another LinkProperties,
    595      * examining both the the base link and all stacked links.
    596      *
    597      * @param target a LinkProperties with the new list of routes
    598      * @return the differences between the routes.
    599      */
    600     public CompareResult<RouteInfo> compareAllRoutes(LinkProperties target) {
    601         /*
    602          * Duplicate the RouteInfos into removed, we will be removing
    603          * routes which are common between mRoutes and target
    604          * leaving the routes that are different. And route address which
    605          * are in target but not in mRoutes are placed in added.
    606          */
    607         CompareResult<RouteInfo> result = new CompareResult<RouteInfo>();
    608 
    609         result.removed = getAllRoutes();
    610         result.added.clear();
    611         if (target != null) {
    612             for (RouteInfo r : target.getAllRoutes()) {
    613                 if (! result.removed.remove(r)) {
    614                     result.added.add(r);
    615                 }
    616             }
    617         }
    618         return result;
    619     }
    620 
    621 
    622     @Override
    623     /**
    624      * generate hashcode based on significant fields
    625      * Equal objects must produce the same hash code, while unequal objects
    626      * may have the same hash codes.
    627      */
    628     public int hashCode() {
    629         return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
    630                 + mLinkAddresses.size() * 31
    631                 + mDnses.size() * 37
    632                 + ((null == mDomains) ? 0 : mDomains.hashCode())
    633                 + mRoutes.size() * 41
    634                 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
    635                 + mStackedLinks.hashCode() * 47)
    636                 + mMtu * 51;
    637     }
    638 
    639     /**
    640      * Implement the Parcelable interface.
    641      */
    642     public void writeToParcel(Parcel dest, int flags) {
    643         dest.writeString(getInterfaceName());
    644         dest.writeInt(mLinkAddresses.size());
    645         for(LinkAddress linkAddress : mLinkAddresses) {
    646             dest.writeParcelable(linkAddress, flags);
    647         }
    648 
    649         dest.writeInt(mDnses.size());
    650         for(InetAddress d : mDnses) {
    651             dest.writeByteArray(d.getAddress());
    652         }
    653         dest.writeString(mDomains);
    654         dest.writeInt(mMtu);
    655         dest.writeInt(mRoutes.size());
    656         for(RouteInfo route : mRoutes) {
    657             dest.writeParcelable(route, flags);
    658         }
    659 
    660         if (mHttpProxy != null) {
    661             dest.writeByte((byte)1);
    662             dest.writeParcelable(mHttpProxy, flags);
    663         } else {
    664             dest.writeByte((byte)0);
    665         }
    666         ArrayList<LinkProperties> stackedLinks = new ArrayList(mStackedLinks.values());
    667         dest.writeList(stackedLinks);
    668     }
    669 
    670     /**
    671      * Implement the Parcelable interface.
    672      */
    673     public static final Creator<LinkProperties> CREATOR =
    674         new Creator<LinkProperties>() {
    675             public LinkProperties createFromParcel(Parcel in) {
    676                 LinkProperties netProp = new LinkProperties();
    677 
    678                 String iface = in.readString();
    679                 if (iface != null) {
    680                     netProp.setInterfaceName(iface);
    681                 }
    682                 int addressCount = in.readInt();
    683                 for (int i=0; i<addressCount; i++) {
    684                     netProp.addLinkAddress((LinkAddress)in.readParcelable(null));
    685                 }
    686                 addressCount = in.readInt();
    687                 for (int i=0; i<addressCount; i++) {
    688                     try {
    689                         netProp.addDns(InetAddress.getByAddress(in.createByteArray()));
    690                     } catch (UnknownHostException e) { }
    691                 }
    692                 netProp.setDomains(in.readString());
    693                 netProp.setMtu(in.readInt());
    694                 addressCount = in.readInt();
    695                 for (int i=0; i<addressCount; i++) {
    696                     netProp.addRoute((RouteInfo)in.readParcelable(null));
    697                 }
    698                 if (in.readByte() == 1) {
    699                     netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
    700                 }
    701                 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
    702                 in.readList(stackedLinks, LinkProperties.class.getClassLoader());
    703                 for (LinkProperties stackedLink: stackedLinks) {
    704                     netProp.addStackedLink(stackedLink);
    705                 }
    706                 return netProp;
    707             }
    708 
    709             public LinkProperties[] newArray(int size) {
    710                 return new LinkProperties[size];
    711             }
    712         };
    713 }
    714