Inet6Address.java revision 4adff24306c86433ce4f771da8489a574e63318e
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.net;
19
20import java.io.IOException;
21import java.io.ObjectInputStream;
22import java.io.ObjectOutputStream;
23import java.io.ObjectStreamField;
24import java.util.Enumeration;
25import org.apache.harmony.luni.util.Inet6Util;
26
27/**
28 * An IPv6 address. See {@link InetAddress}.
29 */
30public final class Inet6Address extends InetAddress {
31
32    private static final long serialVersionUID = 6880410070516793377L;
33
34    static final InetAddress ANY = new Inet6Address(new byte[]
35            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 });
36    static final InetAddress LOOPBACK = new Inet6Address(new byte[]
37            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, "localhost");
38
39    int scope_id;
40
41    boolean scope_id_set;
42
43    boolean scope_ifname_set;
44
45    String ifname;
46
47    /*
48     * scoped interface.
49     */
50    transient NetworkInterface scopedIf;
51
52    Inet6Address(byte address[]) {
53        family = AF_INET6;
54        ipaddress = address;
55        scope_id = 0;
56    }
57
58    Inet6Address(byte address[], String name) {
59        family = AF_INET6;
60        hostName = name;
61        ipaddress = address;
62        scope_id = 0;
63    }
64
65    /**
66     * Constructs an {@code InetAddress} representing the {@code address} and
67     * {@code name} and {@code scope_id}.
68     *
69     * @param address
70     *            the network address.
71     * @param name
72     *            the name associated with the address.
73     * @param scope_id
74     *            the scope id for link- or site-local addresses.
75     */
76    Inet6Address(byte address[], String name, int scope_id) {
77        family = AF_INET6;
78        hostName = name;
79        ipaddress = address;
80        this.scope_id = scope_id;
81        if (scope_id != 0) {
82            scope_id_set = true;
83        }
84    }
85
86    /**
87     * Constructs an IPv6 address according to the given {@code host}, {@code
88     * addr} and {@code scope_id}.
89     *
90     * @param host
91     *            the host name associated with the address.
92     * @param addr
93     *            the network address.
94     * @param scope_id
95     *            the scope id for link- or site-local addresses.
96     * @return the Inet6Address instance representing the IP address.
97     * @throws UnknownHostException
98     *             if the address is null or has an invalid length.
99     */
100    public static Inet6Address getByAddress(String host, byte[] addr,
101            int scope_id) throws UnknownHostException {
102        if (addr == null || addr.length != 16) {
103            throw new UnknownHostException("Illegal IPv6 address");
104        }
105        if (scope_id < 0) {
106            scope_id = 0;
107        }
108        return new Inet6Address(addr, host, scope_id);
109    }
110
111    /**
112     * Gets an IPv6 address instance according to the given {@code host},
113     * {@code addr} and {@code nif}. {@code scope_id} is set according to the
114     * given {@code nif} and the {@code addr} type (for example site-local or
115     * link-local).
116     *
117     * @param host
118     *            the hostname associated with the address.
119     * @param addr
120     *            the network address.
121     * @param nif
122     *            the network interface that this address is associated with.
123     * @return the Inet6Address instance representing the IP address.
124     * @throws UnknownHostException
125     *             if the address is {@code null} or has an invalid length or
126     *             the interface doesn't have a numeric scope id for the given
127     *             address type.
128     */
129    public static Inet6Address getByAddress(String host, byte[] addr,
130            NetworkInterface nif) throws UnknownHostException {
131
132        Inet6Address address = Inet6Address.getByAddress(host, addr, 0);
133
134        // if nif is null, nothing needs to be set.
135        if (null == nif) {
136            return address;
137        }
138
139        // find the first address which matches the type addr,
140        // then set the scope_id, ifname and scopedIf.
141        Enumeration<InetAddress> addressList = nif.getInetAddresses();
142        while (addressList.hasMoreElements()) {
143            InetAddress ia = addressList.nextElement();
144            if (ia.getAddress().length == 16) {
145                Inet6Address v6ia = (Inet6Address) ia;
146                boolean isSameType = v6ia.compareLocalType(address);
147                if (isSameType) {
148                    address.scope_id_set = true;
149                    address.scope_id = v6ia.scope_id;
150                    address.scope_ifname_set = true;
151                    address.ifname = nif.getName();
152                    address.scopedIf = nif;
153                    break;
154                }
155            }
156        }
157        // if no address matches the type of addr, throws an
158        // UnknownHostException.
159        if (!address.scope_id_set) {
160            throw new UnknownHostException("Scope id not found for the given address");
161        }
162        return address;
163    }
164
165    /**
166     * Returns {@code true} if one of following cases applies:
167     * <p>
168     * <ol>
169     *  <li>both addresses are site local</li>
170     *  <li>both addresses are link local</li>
171     *  <li>{@code ia} is neither site local nor link local</li>
172     * </ol>
173     */
174    private boolean compareLocalType(Inet6Address ia) {
175        if (ia.isSiteLocalAddress() && isSiteLocalAddress()) {
176            return true;
177        }
178        if (ia.isLinkLocalAddress() && isLinkLocalAddress()) {
179            return true;
180        }
181        if (!ia.isSiteLocalAddress() && !ia.isLinkLocalAddress()) {
182            return true;
183        }
184        return false;
185    }
186
187    /**
188     * Constructs an {@code InetAddress} representing the {@code address} and
189     * {@code scope_id}.
190     *
191     * @param address
192     *            the network address.
193     * @param scope_id
194     *            the scope id for link- or site-local addresses.
195     */
196    Inet6Address(byte address[], int scope_id) {
197        ipaddress = address;
198        this.scope_id = scope_id;
199        if (scope_id != 0) {
200            scope_id_set = true;
201        }
202    }
203
204    /**
205     * Returns whether this address is an IP multicast address or not. Valid
206     * IPv6 multicast addresses are binary prefixed with 11111111 or FF (hex).
207     *
208     * @return {@code true} if this address is in the multicast group, {@code
209     *         false} otherwise.
210     */
211    @Override
212    public boolean isMulticastAddress() {
213        // Multicast addresses are prefixed with 11111111 (255)
214        return ipaddress[0] == -1;
215    }
216
217    /**
218     * Returns whether this address is a unspecified wildcard address "::" or
219     * not.
220     *
221     * @return {@code true} if this instance represents a wildcard address,
222     *         {@code false} otherwise.
223     */
224    @Override
225    public boolean isAnyLocalAddress() {
226        for (int i = 0; i < ipaddress.length; i++) {
227            if (ipaddress[i] != 0) {
228                return false;
229            }
230        }
231        return true;
232    }
233
234    /**
235     * Returns whether this address is the loopback address or not. The only
236     * valid IPv6 loopback address is "::1".
237     *
238     * @return {@code true} if this instance represents the loopback address,
239     *         {@code false} otherwise.
240     */
241    @Override
242    public boolean isLoopbackAddress() {
243
244        // The last word must be 1
245        if (ipaddress[15] != 1) {
246            return false;
247        }
248
249        // All other words must be 0
250        for (int i = 0; i < 15; i++) {
251            if (ipaddress[i] != 0) {
252                return false;
253            }
254        }
255
256        return true;
257    }
258
259    /**
260     * Returns whether this address is a link-local address or not. A valid IPv6
261     * link-local address is prefixed with 1111111010.
262     *
263     * @return {@code true} if this instance represents a link-local address,
264     *         {@code false} otherwise.
265     */
266    @Override
267    public boolean isLinkLocalAddress() {
268
269        // the first 10 bits need to be 1111111010 (1018)
270        return (ipaddress[0] == -2) && ((ipaddress[1] & 255) >>> 6) == 2;
271    }
272
273    /**
274     * Returns whether this address is a site-local address or not. A valid IPv6
275     * site-local address is prefixed with 1111111011.
276     *
277     * @return {@code true} if this instance represents a site-local address,
278     *         {@code false} otherwise.
279     */
280    @Override
281    public boolean isSiteLocalAddress() {
282
283        // the first 10 bits need to be 1111111011 (1019)
284        return (ipaddress[0] == -2) && ((ipaddress[1] & 255) >>> 6) == 3;
285    }
286
287    /**
288     * Returns whether this address is a global multicast address or not. A
289     * valid IPv6 global multicast address is 11111111xxxx1110 or FF0E hex.
290     *
291     * @return {@code true} if this instance represents a global multicast
292     *         address, {@code false} otherwise.
293     */
294    @Override
295    public boolean isMCGlobal() {
296        // the first byte should be 0xFF and the lower 4 bits
297        // of the second byte should be 0xE
298        return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 14;
299    }
300
301    /**
302     * Returns whether this address is a node-local multicast address or not. A
303     * valid IPv6 node-local multicast address is prefixed with
304     * 11111111xxxx0001.
305     *
306     * @return {@code true} if this instance represents a node-local multicast
307     *         address, {@code false} otherwise.
308     */
309    @Override
310    public boolean isMCNodeLocal() {
311        // the first byte should be 0xFF and the lower 4 bits
312        // of the second byte should be 0x1
313        return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 1;
314    }
315
316    /**
317     * Returns whether this address is a link-local multicast address or not. A
318     * valid IPv6 link-local multicast address is prefixed with
319     * 11111111xxxx0010.
320     *
321     * @return {@code true} if this instance represents a link-local multicast
322     *         address, {@code false} otherwise.
323     */
324    @Override
325    public boolean isMCLinkLocal() {
326        // the first byte should be 0xFF and the lower 4 bits
327        // of the second byte should be 0x2
328        return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 2;
329    }
330
331    /**
332     * Returns whether this address is a site-local multicast address or not. A
333     * valid IPv6 site-local multicast address is prefixed with
334     * 11111111xxxx0101.
335     *
336     * @return {@code true} if this instance represents a site-local multicast
337     *         address, {@code false} otherwise.
338     */
339    @Override
340    public boolean isMCSiteLocal() {
341        // the first byte should be 0xFF and the lower 4 bits
342        // of the second byte should be 0x5
343        return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 5;
344    }
345
346    /**
347     * Returns whether this address is a organization-local multicast address or
348     * not. A valid IPv6 org-local multicast address is prefixed with
349     * 11111111xxxx1000.
350     *
351     * @return {@code true} if this instance represents a org-local multicast
352     *         address, {@code false} otherwise.
353     */
354    @Override
355    public boolean isMCOrgLocal() {
356        // the first byte should be 0xFF and the lower 4 bits
357        // of the second byte should be 0x8
358        return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 8;
359    }
360
361    // BEGIN android-removed
362    // public String getHostAddress() {
363    // }
364    // END android-removed
365
366    /**
367     * Gets the scope id as a number if this address is linked to an interface.
368     * Otherwise returns {@code 0}.
369     *
370     * @return the scope_id of this address or 0 when not linked with an
371     *         interface.
372     */
373    public int getScopeId() {
374        if (scope_id_set) {
375            return scope_id;
376        }
377        return 0;
378    }
379
380    /**
381     * Gets the network interface if this address is instanced with a scoped
382     * network interface. Otherwise returns {@code null}.
383     *
384     * @return the scoped network interface of this address.
385     */
386    public NetworkInterface getScopedInterface() {
387        if (scope_ifname_set) {
388            return scopedIf;
389        }
390        return null;
391    }
392
393    // BEGIN android-removed
394    // public int hashCode() {}
395    // END android-removed
396
397    // BEGIN android-removed
398    // public boolean equals(Object obj) {}
399    // END android-removed
400
401    /**
402     * Returns whether this address is IPv4 compatible or not. An IPv4
403     * compatible address is prefixed with 96 bits of 0's. The last 32-bits are
404     * varied corresponding with the 32-bit IPv4 address space.
405     *
406     * @return {@code true} if this instance represents an IPv4 compatible
407     *         address, {@code false} otherwise.
408     */
409    public boolean isIPv4CompatibleAddress() {
410        for (int i = 0; i < 12; i++) {
411            if (ipaddress[i] != 0) {
412                return false;
413            }
414        }
415        return true;
416    }
417
418    private static final ObjectStreamField[] serialPersistentFields = {
419            new ObjectStreamField("ipaddress", new byte[0].getClass()),
420            new ObjectStreamField("scope_id", Integer.TYPE),
421            new ObjectStreamField("scope_id_set", Boolean.TYPE),
422            new ObjectStreamField("scope_ifname_set", Boolean.TYPE),
423            new ObjectStreamField("ifname", String.class), };
424
425    private void writeObject(ObjectOutputStream stream) throws IOException {
426        ObjectOutputStream.PutField fields = stream.putFields();
427        if (ipaddress == null) {
428            fields.put("ipaddress", null);
429        } else {
430            fields.put("ipaddress", ipaddress);
431        }
432
433        fields.put("scope_id", scope_id);
434        fields.put("scope_id_set", scope_id_set);
435        fields.put("scope_ifname_set", scope_ifname_set);
436        fields.put("ifname", ifname);
437        stream.writeFields();
438    }
439
440    private void readObject(ObjectInputStream stream) throws IOException,
441            ClassNotFoundException {
442        ObjectInputStream.GetField fields = stream.readFields();
443        ipaddress = (byte[]) fields.get("ipaddress", null);
444        scope_id = fields.get("scope_id", 0);
445        scope_id_set = fields.get("scope_id_set", false);
446        ifname = (String) fields.get("ifname", null);
447        scope_ifname_set = fields.get("scope_ifname_set", false);
448        if (scope_ifname_set && null != ifname) {
449            scopedIf = NetworkInterface.getByName(ifname);
450        }
451    }
452
453    /**
454     * Returns a string containing a concise, human-readable description of this
455     * IP address.
456     *
457     * @return the description, as host/address.
458     */
459    @Override
460    public String toString() {
461        if (ifname != null) {
462            return super.toString() + "%" + ifname;
463        }
464        if (scope_id != 0) {
465            return super.toString() + "%" + scope_id;
466        }
467        return super.toString();
468    }
469}
470