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