LinkAddress.java revision 34385d352da19805ae948215e2edbeedd16b7941
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.os.Parcel;
20import android.os.Parcelable;
21
22import java.net.Inet4Address;
23import java.net.InetAddress;
24import java.net.InterfaceAddress;
25import java.net.UnknownHostException;
26
27import static android.system.OsConstants.IFA_F_DADFAILED;
28import static android.system.OsConstants.IFA_F_DEPRECATED;
29import static android.system.OsConstants.IFA_F_TENTATIVE;
30import static android.system.OsConstants.RT_SCOPE_HOST;
31import static android.system.OsConstants.RT_SCOPE_LINK;
32import static android.system.OsConstants.RT_SCOPE_SITE;
33import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
34
35/**
36 * Identifies an IP address on a network link.
37 *
38 * A {@code LinkAddress} consists of:
39 * <ul>
40 * <li>An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}).
41 * The address must be unicast, as multicast addresses cannot be assigned to interfaces.
42 * <li>Address flags: A bitmask of {@code IFA_F_*} values representing properties of the address.
43 * <li>Address scope: An integer defining the scope in which the address is unique (e.g.,
44 * {@code RT_SCOPE_LINK} or {@code RT_SCOPE_SITE}).
45 * <ul>
46 *<p>
47 * When constructing a {@code LinkAddress}, the IP address and prefix are required. The flags and
48 * scope are optional. If they are not specified, the flags are set to zero, and the scope will be
49 * determined based on the IP address (e.g., link-local addresses will be created with a scope of
50 * {@code RT_SCOPE_LINK}, global addresses with {@code RT_SCOPE_UNIVERSE}, etc.) If they are
51 * specified, they are not checked for validity.
52 *
53 * @hide
54 */
55public class LinkAddress implements Parcelable {
56    /**
57     * IPv4 or IPv6 address.
58     */
59    private InetAddress address;
60
61    /**
62     * Prefix length.
63     */
64    private int prefixLength;
65
66    /**
67     * Address flags. A bitmask of IFA_F_* values.
68     */
69    private int flags;
70
71    /**
72     * Address scope. One of the RT_SCOPE_* constants.
73     */
74    private int scope;
75
76    /**
77     * Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and
78     * RFC 6724 section 3.2.
79     * @hide
80     */
81    static int scopeForUnicastAddress(InetAddress addr) {
82        if (addr.isAnyLocalAddress()) {
83            return RT_SCOPE_HOST;
84        }
85
86        if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
87            return RT_SCOPE_LINK;
88        }
89
90        // isSiteLocalAddress() returns true for private IPv4 addresses, but RFC 6724 section 3.2
91        // says that they are assigned global scope.
92        if (!(addr instanceof Inet4Address) && addr.isSiteLocalAddress()) {
93            return RT_SCOPE_SITE;
94        }
95
96        return RT_SCOPE_UNIVERSE;
97    }
98
99    /**
100     * Utility function for the constructors.
101     */
102    private void init(InetAddress address, int prefixLength, int flags, int scope) {
103        if (address == null ||
104                address.isMulticastAddress() ||
105                prefixLength < 0 ||
106                ((address instanceof Inet4Address) && prefixLength > 32) ||
107                (prefixLength > 128)) {
108            throw new IllegalArgumentException("Bad LinkAddress params " + address +
109                    "/" + prefixLength);
110        }
111        this.address = address;
112        this.prefixLength = prefixLength;
113        this.flags = flags;
114        this.scope = scope;
115    }
116
117    /**
118     * Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with
119     * the specified flags and scope. Flags and scope are not checked for validity.
120     * @param address The IP address.
121     * @param prefixLength The prefix length.
122     */
123    public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) {
124        init(address, prefixLength, flags, scope);
125    }
126
127    /**
128     * Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length.
129     * The flags are set to zero and the scope is determined from the address.
130     * @param address The IP address.
131     * @param prefixLength The prefix length.
132     */
133    public LinkAddress(InetAddress address, int prefixLength) {
134        this(address, prefixLength, 0, 0);
135        this.scope = scopeForUnicastAddress(address);
136    }
137
138    /**
139     * Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}.
140     * The flags are set to zero and the scope is determined from the address.
141     * @param interfaceAddress The interface address.
142     */
143    public LinkAddress(InterfaceAddress interfaceAddress) {
144        this(interfaceAddress.getAddress(),
145             interfaceAddress.getNetworkPrefixLength());
146    }
147
148    /**
149     * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
150     * "2001:db8::1/64". The flags are set to zero and the scope is determined from the address.
151     * @param string The string to parse.
152     */
153    public LinkAddress(String address) {
154        this(address, 0, 0);
155        this.scope = scopeForUnicastAddress(this.address);
156    }
157
158    /**
159     * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
160     * "2001:db8::1/64", with the specified flags and scope.
161     * @param string The string to parse.
162     * @param flags The address flags.
163     * @param scope The address scope.
164     */
165    public LinkAddress(String address, int flags, int scope) {
166        InetAddress inetAddress = null;
167        int prefixLength = -1;
168        try {
169            String [] pieces = address.split("/", 2);
170            prefixLength = Integer.parseInt(pieces[1]);
171            inetAddress = InetAddress.parseNumericAddress(pieces[0]);
172        } catch (NullPointerException e) {            // Null string.
173        } catch (ArrayIndexOutOfBoundsException e) {  // No prefix length.
174        } catch (NumberFormatException e) {           // Non-numeric prefix.
175        } catch (IllegalArgumentException e) {        // Invalid IP address.
176        }
177
178        if (inetAddress == null || prefixLength == -1) {
179            throw new IllegalArgumentException("Bad LinkAddress params " + address);
180        }
181
182        init(inetAddress, prefixLength, flags, scope);
183    }
184
185    /**
186     * Returns a string representation of this address, such as "192.0.2.1/24" or "2001:db8::1/64".
187     * The string representation does not contain the flags and scope, just the address and prefix
188     * length.
189     */
190    @Override
191    public String toString() {
192        return address.getHostAddress() + "/" + prefixLength;
193    }
194
195    /**
196     * Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if
197     * their address, prefix length, flags and scope are equal.
198     *
199     * @param obj the object to be tested for equality.
200     * @return {@code true} if both objects are equal, {@code false} otherwise.
201     */
202    @Override
203    public boolean equals(Object obj) {
204        if (!(obj instanceof LinkAddress)) {
205            return false;
206        }
207        LinkAddress linkAddress = (LinkAddress) obj;
208        return this.address.equals(linkAddress.address) &&
209            this.prefixLength == linkAddress.prefixLength &&
210            this.flags == linkAddress.flags &&
211            this.scope == linkAddress.scope;
212    }
213
214    /**
215     * Returns a hashcode for this address.
216     */
217    @Override
218    public int hashCode() {
219        return address.hashCode() + 11 * prefixLength + 19 * flags + 43 * scope;
220    }
221
222    /**
223     * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress} represent
224     * the same address. Two LinkAddresses represent the same address if they have the same IP
225     * address and prefix length, even if their properties are different.
226     *
227     * @param other the {@code LinkAddress} to compare to.
228     * @return {@code true} if both objects have the same address and prefix length, {@code false}
229     * otherwise.
230     */
231    public boolean isSameAddressAs(LinkAddress other) {
232        return address.equals(other.address) && prefixLength == other.prefixLength;
233    }
234
235    /**
236     * Returns the InetAddress of this address.
237     */
238    public InetAddress getAddress() {
239        return address;
240    }
241
242    /**
243     * Returns the prefix length of this address.
244     */
245    public int getNetworkPrefixLength() {
246        return prefixLength;
247    }
248
249    /**
250     * Returns the flags of this address.
251     */
252    public int getFlags() {
253        return flags;
254    }
255
256    /**
257     * Returns the scope of this address.
258     */
259    public int getScope() {
260        return scope;
261    }
262
263    /**
264     * Returns true if this {@code LinkAddress} is global scope and preferred.
265     */
266    public boolean isGlobalPreferred() {
267        return (scope == RT_SCOPE_UNIVERSE &&
268                (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED | IFA_F_TENTATIVE)) == 0L);
269    }
270
271    /**
272     * Implement the Parcelable interface.
273     * @hide
274     */
275    public int describeContents() {
276        return 0;
277    }
278
279    /**
280     * Implement the Parcelable interface.
281     * @hide
282     */
283    public void writeToParcel(Parcel dest, int flags) {
284        dest.writeByteArray(address.getAddress());
285        dest.writeInt(prefixLength);
286        dest.writeInt(this.flags);
287        dest.writeInt(scope);
288    }
289
290    /**
291     * Implement the Parcelable interface.
292     * @hide
293     */
294    public static final Creator<LinkAddress> CREATOR =
295        new Creator<LinkAddress>() {
296            public LinkAddress createFromParcel(Parcel in) {
297                InetAddress address = null;
298                try {
299                    address = InetAddress.getByAddress(in.createByteArray());
300                } catch (UnknownHostException e) {
301                    // Nothing we can do here. When we call the constructor, we'll throw an
302                    // IllegalArgumentException, because a LinkAddress can't have a null
303                    // InetAddress.
304                }
305                int prefixLength = in.readInt();
306                int flags = in.readInt();
307                int scope = in.readInt();
308                return new LinkAddress(address, prefixLength, flags, scope);
309            }
310
311            public LinkAddress[] newArray(int size) {
312                return new LinkAddress[size];
313            }
314        };
315}
316