1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.  Oracle designates this
9 * particular file as subject to the "Classpath" exception as provided
10 * by Oracle in the LICENSE file that accompanied this code.
11 *
12 * This code is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 * version 2 for more details (a copy is included in the LICENSE file that
16 * accompanied this code).
17 *
18 * You should have received a copy of the GNU General Public License version
19 * 2 along with this work; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23 * or visit www.oracle.com if you need additional information or have any
24 * questions.
25 */
26
27package java.net;
28
29import java.io.IOException;
30import java.io.InvalidObjectException;
31import java.io.ObjectInputStream;
32import java.io.ObjectOutputStream;
33import java.io.ObjectStreamField;
34import java.util.Enumeration;
35import java.util.Arrays;
36import libcore.io.Libcore;
37import static android.system.OsConstants.*;
38
39/**
40 * This class represents an Internet Protocol version 6 (IPv6) address.
41 * Defined by <a href="http://www.ietf.org/rfc/rfc2373.txt">
42 * <i>RFC&nbsp;2373: IP Version 6 Addressing Architecture</i></a>.
43 *
44 * <h3> <A NAME="format">Textual representation of IP addresses</a> </h3>
45 *
46 * Textual representation of IPv6 address used as input to methods
47 * takes one of the following forms:
48 *
49 * <ol>
50 *   <li><p> <A NAME="lform">The preferred form</a> is x:x:x:x:x:x:x:x,
51 *   where the 'x's are
52 *   the hexadecimal values of the eight 16-bit pieces of the
53 *   address. This is the full form.  For example,
54 *
55 *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
56 *   <tr><td>{@code 1080:0:0:0:8:800:200C:417A}<td></tr>
57 *   </table></blockquote>
58 *
59 *   <p> Note that it is not necessary to write the leading zeros in
60 *   an individual field. However, there must be at least one numeral
61 *   in every field, except as described below.</li>
62 *
63 *   <li><p> Due to some methods of allocating certain styles of IPv6
64 *   addresses, it will be common for addresses to contain long
65 *   strings of zero bits. In order to make writing addresses
66 *   containing zero bits easier, a special syntax is available to
67 *   compress the zeros. The use of "::" indicates multiple groups
68 *   of 16-bits of zeros. The "::" can only appear once in an address.
69 *   The "::" can also be used to compress the leading and/or trailing
70 *   zeros in an address. For example,
71 *
72 *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
73 *   <tr><td>{@code 1080::8:800:200C:417A}<td></tr>
74 *   </table></blockquote>
75 *
76 *   <li><p> An alternative form that is sometimes more convenient
77 *   when dealing with a mixed environment of IPv4 and IPv6 nodes is
78 *   x:x:x:x:x:x:d.d.d.d, where the 'x's are the hexadecimal values
79 *   of the six high-order 16-bit pieces of the address, and the 'd's
80 *   are the decimal values of the four low-order 8-bit pieces of the
81 *   standard IPv4 representation address, for example,
82 *
83 *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
84 *   <tr><td>{@code ::FFFF:129.144.52.38}<td></tr>
85 *   <tr><td>{@code ::129.144.52.38}<td></tr>
86 *   </table></blockquote>
87 *
88 *   <p> where "::FFFF:d.d.d.d" and "::d.d.d.d" are, respectively, the
89 *   general forms of an IPv4-mapped IPv6 address and an
90 *   IPv4-compatible IPv6 address. Note that the IPv4 portion must be
91 *   in the "d.d.d.d" form. The following forms are invalid:
92 *
93 *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
94 *   <tr><td>{@code ::FFFF:d.d.d}<td></tr>
95 *   <tr><td>{@code ::FFFF:d.d}<td></tr>
96 *   <tr><td>{@code ::d.d.d}<td></tr>
97 *   <tr><td>{@code ::d.d}<td></tr>
98 *   </table></blockquote>
99 *
100 *   <p> The following form:
101 *
102 *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
103 *   <tr><td>{@code ::FFFF:d}<td></tr>
104 *   </table></blockquote>
105 *
106 *   <p> is valid, however it is an unconventional representation of
107 *   the IPv4-compatible IPv6 address,
108 *
109 *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
110 *   <tr><td>{@code ::255.255.0.d}<td></tr>
111 *   </table></blockquote>
112 *
113 *   <p> while "::d" corresponds to the general IPv6 address
114 *   "0:0:0:0:0:0:0:d".</li>
115 * </ol>
116 *
117 * <p> For methods that return a textual representation as output
118 * value, the full form is used. Inet6Address will return the full
119 * form because it is unambiguous when used in combination with other
120 * textual data.
121 *
122 * <h4> Special IPv6 address </h4>
123 *
124 * <blockquote>
125 * <table cellspacing=2 summary="Description of IPv4-mapped address">
126 * <tr><th valign=top><i>IPv4-mapped address</i></th>
127 *         <td>Of the form::ffff:w.x.y.z, this IPv6 address is used to
128 *         represent an IPv4 address. It allows the native program to
129 *         use the same address data structure and also the same
130 *         socket when communicating with both IPv4 and IPv6 nodes.
131 *
132 *         <p>In InetAddress and Inet6Address, it is used for internal
133 *         representation; it has no functional role. Java will never
134 *         return an IPv4-mapped address.  These classes can take an
135 *         IPv4-mapped address as input, both in byte array and text
136 *         representation. However, it will be converted into an IPv4
137 *         address.</td></tr>
138 * </table></blockquote>
139 *
140 * <h4><A NAME="scoped">Textual representation of IPv6 scoped addresses</a></h4>
141 *
142 * <p> The textual representation of IPv6 addresses as described above can be
143 * extended to specify IPv6 scoped addresses. This extension to the basic
144 * addressing architecture is described in [draft-ietf-ipngwg-scoping-arch-04.txt].
145 *
146 * <p> Because link-local and site-local addresses are non-global, it is possible
147 * that different hosts may have the same destination address and may be
148 * reachable through different interfaces on the same originating system. In
149 * this case, the originating system is said to be connected to multiple zones
150 * of the same scope. In order to disambiguate which is the intended destination
151 * zone, it is possible to append a zone identifier (or <i>scope_id</i>) to an
152 * IPv6 address.
153 *
154 * <p> The general format for specifying the <i>scope_id</i> is the following:
155 *
156 * <blockquote><i>IPv6-address</i>%<i>scope_id</i></blockquote>
157 * <p> The IPv6-address is a literal IPv6 address as described above.
158 * The <i>scope_id</i> refers to an interface on the local system, and it can be
159 * specified in two ways.
160 * <ol><li><i>As a numeric identifier.</i> This must be a positive integer
161 * that identifies the particular interface and scope as understood by the
162 * system. Usually, the numeric values can be determined through administration
163 * tools on the system. Each interface may have multiple values, one for each
164 * scope. If the scope is unspecified, then the default value used is zero.</li>
165 * <li><i>As a string.</i> This must be the exact string that is returned by
166 * {@link java.net.NetworkInterface#getName()} for the particular interface in
167 * question. When an Inet6Address is created in this way, the numeric scope-id
168 * is determined at the time the object is created by querying the relevant
169 * NetworkInterface.</li></ol>
170 *
171 * <p> Note also, that the numeric <i>scope_id</i> can be retrieved from
172 * Inet6Address instances returned from the NetworkInterface class. This can be
173 * used to find out the current scope ids configured on the system.
174 * @since 1.4
175 */
176
177public final
178class Inet6Address extends InetAddress {
179    final static int INADDRSZ = 16;
180
181    /** @hide */
182    public static final InetAddress ANY =
183            new Inet6Address("::", new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0);
184
185    /** @hide */
186    public static final InetAddress LOOPBACK = new Inet6Address("ip6-localhost",
187            new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 0);
188
189    private class Inet6AddressHolder {
190
191        private Inet6AddressHolder() {
192            ipaddress = new byte[INADDRSZ];
193        }
194
195        private Inet6AddressHolder(
196            byte[] ipaddress, int scope_id, boolean scope_id_set,
197            NetworkInterface ifname, boolean scope_ifname_set)
198        {
199            this.ipaddress = ipaddress;
200            this.scope_id = scope_id;
201            this.scope_id_set = scope_id_set;
202            this.scope_ifname_set = scope_ifname_set;
203            this.scope_ifname = ifname;
204        }
205
206        /**
207         * Holds a 128-bit (16 bytes) IPv6 address.
208         */
209        byte[] ipaddress;
210
211        /**
212         * scope_id. The scope specified when the object is created. If the object
213         * is created with an interface name, then the scope_id is not determined
214         * until the time it is needed.
215         */
216        int scope_id;  // 0
217
218        /**
219         * This will be set to true when the scope_id field contains a valid
220         * integer scope_id.
221         */
222        boolean scope_id_set;  // false
223
224        /**
225         * scoped interface. scope_id is derived from this as the scope_id of the first
226         * address whose scope is the same as this address for the named interface.
227         */
228        NetworkInterface scope_ifname;  // null
229
230        /**
231         * set if the object is constructed with a scoped
232         * interface instead of a numeric scope id.
233         */
234        boolean scope_ifname_set; // false;
235
236        void setAddr(byte addr[]) {
237            if (addr.length == INADDRSZ) { // normal IPv6 address
238                System.arraycopy(addr, 0, ipaddress, 0, INADDRSZ);
239            }
240        }
241
242        void init(byte addr[], int scope_id) {
243            setAddr(addr);
244
245            // Android-changed: was >= 0
246            if (scope_id > 0) {
247                this.scope_id = scope_id;
248                this.scope_id_set = true;
249            }
250        }
251
252        void init(byte addr[], NetworkInterface nif)
253            throws UnknownHostException
254        {
255            setAddr(addr);
256
257            if (nif != null) {
258                this.scope_id = deriveNumericScope(ipaddress, nif);
259                this.scope_id_set = true;
260                this.scope_ifname = nif;
261                this.scope_ifname_set = true;
262            }
263        }
264
265        /* ----- Android-removed -----
266        String getHostAddress() {
267            String s = numericToTextFormat(ipaddress);
268            if (scope_ifname != null) { // must check this first
269                s = s + "%" + scope_ifname.getName();
270            } else if (scope_id_set) {
271                s = s + "%" + scope_id;
272            }
273            return s;
274        } */
275
276        public boolean equals(Object o) {
277            if (! (o instanceof Inet6AddressHolder)) {
278                return false;
279            }
280            Inet6AddressHolder that = (Inet6AddressHolder)o;
281
282            return Arrays.equals(this.ipaddress, that.ipaddress);
283        }
284
285        public int hashCode() {
286            if (ipaddress != null) {
287
288                int hash = 0;
289                int i=0;
290                while (i<INADDRSZ) {
291                    int j=0;
292                    int component=0;
293                    while (j<4 && i<INADDRSZ) {
294                        component = (component << 8) + ipaddress[i];
295                        j++;
296                        i++;
297                    }
298                    hash += component;
299                }
300                return hash;
301
302            } else {
303                return 0;
304            }
305        }
306
307        boolean isIPv4CompatibleAddress() {
308            if ((ipaddress[0] == 0x00) && (ipaddress[1] == 0x00) &&
309                (ipaddress[2] == 0x00) && (ipaddress[3] == 0x00) &&
310                (ipaddress[4] == 0x00) && (ipaddress[5] == 0x00) &&
311                (ipaddress[6] == 0x00) && (ipaddress[7] == 0x00) &&
312                (ipaddress[8] == 0x00) && (ipaddress[9] == 0x00) &&
313                (ipaddress[10] == 0x00) && (ipaddress[11] == 0x00))  {
314                return true;
315            }
316            return false;
317        }
318
319        boolean isMulticastAddress() {
320            return ((ipaddress[0] & 0xff) == 0xff);
321        }
322
323        boolean isAnyLocalAddress() {
324            byte test = 0x00;
325            for (int i = 0; i < INADDRSZ; i++) {
326                test |= ipaddress[i];
327            }
328            return (test == 0x00);
329        }
330
331        boolean isLoopbackAddress() {
332            byte test = 0x00;
333            for (int i = 0; i < 15; i++) {
334                test |= ipaddress[i];
335            }
336            return (test == 0x00) && (ipaddress[15] == 0x01);
337        }
338
339        boolean isLinkLocalAddress() {
340            return ((ipaddress[0] & 0xff) == 0xfe
341                    && (ipaddress[1] & 0xc0) == 0x80);
342        }
343
344
345        boolean isSiteLocalAddress() {
346            return ((ipaddress[0] & 0xff) == 0xfe
347                    && (ipaddress[1] & 0xc0) == 0xc0);
348        }
349
350        boolean isMCGlobal() {
351            return ((ipaddress[0] & 0xff) == 0xff
352                    && (ipaddress[1] & 0x0f) == 0x0e);
353        }
354
355        boolean isMCNodeLocal() {
356            return ((ipaddress[0] & 0xff) == 0xff
357                    && (ipaddress[1] & 0x0f) == 0x01);
358        }
359
360        boolean isMCLinkLocal() {
361            return ((ipaddress[0] & 0xff) == 0xff
362                    && (ipaddress[1] & 0x0f) == 0x02);
363        }
364
365        boolean isMCSiteLocal() {
366            return ((ipaddress[0] & 0xff) == 0xff
367                    && (ipaddress[1] & 0x0f) == 0x05);
368        }
369
370        boolean isMCOrgLocal() {
371            return ((ipaddress[0] & 0xff) == 0xff
372                    && (ipaddress[1] & 0x0f) == 0x08);
373        }
374    }
375
376    private final transient Inet6AddressHolder holder6;
377
378    private static final long serialVersionUID = 6880410070516793377L;
379
380    Inet6Address() {
381        super();
382        holder.init(null, AF_INET6);
383        holder6 = new Inet6AddressHolder();
384    }
385
386    /* checking of value for scope_id should be done by caller
387     * scope_id must be >= 0, or -1 to indicate not being set
388     */
389    Inet6Address(String hostName, byte addr[], int scope_id) {
390        holder.init(hostName, AF_INET6);
391        holder6 = new Inet6AddressHolder();
392        holder6.init(addr, scope_id);
393    }
394
395    Inet6Address(String hostName, byte addr[]) {
396        holder6 = new Inet6AddressHolder();
397        try {
398            initif (hostName, addr, null);
399        } catch (UnknownHostException e) {} /* cant happen if ifname is null */
400    }
401
402    Inet6Address (String hostName, byte addr[], NetworkInterface nif) throws UnknownHostException {
403        holder6 = new Inet6AddressHolder();
404        initif (hostName, addr, nif);
405    }
406
407    Inet6Address (String hostName, byte addr[], String ifname) throws UnknownHostException {
408        holder6 = new Inet6AddressHolder();
409        initstr (hostName, addr, ifname);
410    }
411
412    /**
413     * Create an Inet6Address in the exact manner of {@link
414     * InetAddress#getByAddress(String,byte[])} except that the IPv6 scope_id is
415     * set to the value corresponding to the given interface for the address
416     * type specified in {@code addr}. The call will fail with an
417     * UnknownHostException if the given interface does not have a numeric
418     * scope_id assigned for the given address type (eg. link-local or site-local).
419     * See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6
420     * scoped addresses.
421     *
422     * @param host the specified host
423     * @param addr the raw IP address in network byte order
424     * @param nif an interface this address must be associated with.
425     * @return  an Inet6Address object created from the raw IP address.
426     * @throws  UnknownHostException
427     *          if IP address is of illegal length, or if the interface does not
428     *          have a numeric scope_id assigned for the given address type.
429     *
430     * @since 1.5
431     */
432    public static Inet6Address getByAddress(String host, byte[] addr,
433                                            NetworkInterface nif)
434        throws UnknownHostException
435    {
436        if (host != null && host.length() > 0 && host.charAt(0) == '[') {
437            if (host.charAt(host.length()-1) == ']') {
438                host = host.substring(1, host.length() -1);
439            }
440        }
441        if (addr != null) {
442            if (addr.length == Inet6Address.INADDRSZ) {
443                return new Inet6Address(host, addr, nif);
444            }
445        }
446        throw new UnknownHostException("addr is of illegal length");
447    }
448
449    /**
450     * Create an Inet6Address in the exact manner of {@link
451     * InetAddress#getByAddress(String,byte[])} except that the IPv6 scope_id is
452     * set to the given numeric value. The scope_id is not checked to determine
453     * if it corresponds to any interface on the system.
454     * See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6
455     * scoped addresses.
456     *
457     * @param host the specified host
458     * @param addr the raw IP address in network byte order
459     * @param scope_id the numeric scope_id for the address.
460     * @return  an Inet6Address object created from the raw IP address.
461     * @throws  UnknownHostException  if IP address is of illegal length.
462     *
463     * @since 1.5
464     */
465    public static Inet6Address getByAddress(String host, byte[] addr,
466                                            int scope_id)
467        throws UnknownHostException
468    {
469        if (host != null && host.length() > 0 && host.charAt(0) == '[') {
470            if (host.charAt(host.length()-1) == ']') {
471                host = host.substring(1, host.length() -1);
472            }
473        }
474        if (addr != null) {
475            if (addr.length == Inet6Address.INADDRSZ) {
476                return new Inet6Address(host, addr, scope_id);
477            }
478        }
479        throw new UnknownHostException("addr is of illegal length");
480    }
481
482    private void initstr(String hostName, byte addr[], String ifname)
483        throws UnknownHostException
484    {
485        try {
486            NetworkInterface nif = NetworkInterface.getByName (ifname);
487            if (nif == null) {
488                throw new UnknownHostException ("no such interface " + ifname);
489            }
490            initif (hostName, addr, nif);
491        } catch (SocketException e) {
492            throw new UnknownHostException ("SocketException thrown" + ifname);
493        }
494    }
495
496    private void initif(String hostName, byte addr[],NetworkInterface nif) throws UnknownHostException {
497        holder().hostName = hostName;
498        int family = -1;
499        holder6.init(addr, nif);
500
501        if (addr.length == INADDRSZ) { // normal IPv6 address
502            family = AF_INET6;
503        }
504        holder.init(hostName, family);
505    }
506
507    /* check the two Ipv6 addresses and return false if they are both
508     * non global address types, but not the same.
509     * (ie. one is sitelocal and the other linklocal)
510     * return true otherwise.
511     */
512
513    private static boolean isDifferentLocalAddressType(
514        byte[] thisAddr, byte[] otherAddr) {
515
516        if (Inet6Address.isLinkLocalAddress(thisAddr) &&
517                !Inet6Address.isLinkLocalAddress(otherAddr)) {
518            return false;
519        }
520        if (Inet6Address.isSiteLocalAddress(thisAddr) &&
521                !Inet6Address.isSiteLocalAddress(otherAddr)) {
522            return false;
523        }
524        return true;
525    }
526
527    private static int deriveNumericScope (byte[] thisAddr, NetworkInterface ifc) throws UnknownHostException {
528        Enumeration<InetAddress> addresses = ifc.getInetAddresses();
529        while (addresses.hasMoreElements()) {
530            InetAddress addr = addresses.nextElement();
531            if (!(addr instanceof Inet6Address)) {
532                continue;
533            }
534            Inet6Address ia6_addr = (Inet6Address)addr;
535            /* check if site or link local prefixes match */
536            if (!isDifferentLocalAddressType(thisAddr, ia6_addr.getAddress())){
537                /* type not the same, so carry on searching */
538                continue;
539            }
540            /* found a matching address - return its scope_id */
541            return ia6_addr.getScopeId();
542        }
543        throw new UnknownHostException ("no scope_id found");
544    }
545
546    private int deriveNumericScope (String ifname) throws UnknownHostException {
547        Enumeration<NetworkInterface> en;
548        try {
549            en = NetworkInterface.getNetworkInterfaces();
550        } catch (SocketException e) {
551            throw new UnknownHostException ("could not enumerate local network interfaces");
552        }
553        while (en.hasMoreElements()) {
554            NetworkInterface ifc = en.nextElement();
555            if (ifc.getName().equals (ifname)) {
556                return deriveNumericScope(holder6.ipaddress, ifc);
557            }
558        }
559        throw new UnknownHostException ("No matching address found for interface : " +ifname);
560    }
561
562    /**
563     * @serialField ipaddress byte[]
564     * @serialField scope_id int
565     * @serialField scope_id_set boolean
566     * @serialField scope_ifname_set boolean
567     * @serialField ifname String
568     */
569
570    private static final ObjectStreamField[] serialPersistentFields = {
571         new ObjectStreamField("ipaddress", byte[].class),
572         new ObjectStreamField("scope_id", int.class),
573         new ObjectStreamField("scope_id_set", boolean.class),
574         new ObjectStreamField("scope_ifname_set", boolean.class),
575         new ObjectStreamField("ifname", String.class)
576    };
577
578    private static final long FIELDS_OFFSET;
579    private static final sun.misc.Unsafe UNSAFE;
580
581    static {
582        try {
583            sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
584            FIELDS_OFFSET = unsafe.objectFieldOffset(
585                    Inet6Address.class.getDeclaredField("holder6"));
586            UNSAFE = unsafe;
587        } catch (ReflectiveOperationException e) {
588            throw new Error(e);
589        }
590    }
591
592    /**
593     * restore the state of this object from stream
594     * including the scope information, only if the
595     * scoped interface name is valid on this system
596     */
597    private void readObject(ObjectInputStream s)
598        throws IOException, ClassNotFoundException {
599        NetworkInterface scope_ifname = null;
600
601        // Android-changed: was getClass().getClassLoader() != null
602        if (getClass().getClassLoader() != Class.class.getClassLoader()) {
603            throw new SecurityException ("invalid address type");
604        }
605
606        ObjectInputStream.GetField gf = s.readFields();
607        byte[] ipaddress = (byte[])gf.get("ipaddress", null);
608        int scope_id = (int)gf.get("scope_id", -1);
609        boolean scope_id_set = (boolean)gf.get("scope_id_set", false);
610        boolean scope_ifname_set = (boolean)gf.get("scope_ifname_set", false);
611        String ifname = (String)gf.get("ifname", null);
612
613        if (ifname != null && !"".equals (ifname)) {
614            try {
615                scope_ifname = NetworkInterface.getByName(ifname);
616                if (scope_ifname == null) {
617                    /* the interface does not exist on this system, so we clear
618                     * the scope information completely */
619                    scope_id_set = false;
620                    scope_ifname_set = false;
621                    scope_id = 0;
622                } else {
623                    scope_ifname_set = true;
624                    try {
625                        scope_id = deriveNumericScope (ipaddress, scope_ifname);
626                    } catch (UnknownHostException e) {
627                        // typically should not happen, but it may be that
628                        // the machine being used for deserialization has
629                        // the same interface name but without IPv6 configured.
630                    }
631                }
632            } catch (SocketException e) {}
633        }
634
635        /* if ifname was not supplied, then the numeric info is used */
636
637        ipaddress = ipaddress.clone();
638
639        // Check that our invariants are satisfied
640        if (ipaddress.length != INADDRSZ) {
641            throw new InvalidObjectException("invalid address length: "+
642                                             ipaddress.length);
643        }
644
645        if (holder().getFamily() != AF_INET6) {
646            throw new InvalidObjectException("invalid address family type");
647        }
648
649        Inet6AddressHolder h = new Inet6AddressHolder(
650            ipaddress, scope_id, scope_id_set, scope_ifname, scope_ifname_set
651        );
652
653        UNSAFE.putObject(this, FIELDS_OFFSET, h);
654    }
655
656    /**
657     * default behavior is overridden in order to write the
658     * scope_ifname field as a String, rather than a NetworkInterface
659     * which is not serializable
660     */
661    private synchronized void writeObject(ObjectOutputStream s)
662        throws IOException
663    {
664            String ifname = null;
665
666        if (holder6.scope_ifname != null) {
667            ifname = holder6.scope_ifname.getName();
668            holder6.scope_ifname_set = true;
669        }
670        ObjectOutputStream.PutField pfields = s.putFields();
671        pfields.put("ipaddress", holder6.ipaddress);
672        pfields.put("scope_id", holder6.scope_id);
673        pfields.put("scope_id_set", holder6.scope_id_set);
674        pfields.put("scope_ifname_set", holder6.scope_ifname_set);
675        pfields.put("ifname", ifname);
676        s.writeFields();
677    }
678
679    /**
680     * Utility routine to check if the InetAddress is an IP multicast
681     * address. 11111111 at the start of the address identifies the
682     * address as being a multicast address.
683     *
684     * @return a {@code boolean} indicating if the InetAddress is an IP
685     *         multicast address
686     *
687     * @since JDK1.1
688     */
689    @Override
690    public boolean isMulticastAddress() {
691        return holder6.isMulticastAddress();
692    }
693
694    /**
695     * Utility routine to check if the InetAddress in a wildcard address.
696     *
697     * @return a {@code boolean} indicating if the Inetaddress is
698     *         a wildcard address.
699     *
700     * @since 1.4
701     */
702    @Override
703    public boolean isAnyLocalAddress() {
704        return holder6.isAnyLocalAddress();
705    }
706
707    /**
708     * Utility routine to check if the InetAddress is a loopback address.
709     *
710     * @return a {@code boolean} indicating if the InetAddress is a loopback
711     *         address; or false otherwise.
712     *
713     * @since 1.4
714     */
715    @Override
716    public boolean isLoopbackAddress() {
717        return holder6.isLoopbackAddress();
718    }
719
720    /**
721     * Utility routine to check if the InetAddress is an link local address.
722     *
723     * @return a {@code boolean} indicating if the InetAddress is a link local
724     *         address; or false if address is not a link local unicast address.
725     *
726     * @since 1.4
727     */
728    @Override
729    public boolean isLinkLocalAddress() {
730        return holder6.isLinkLocalAddress();
731    }
732
733    /* static version of above */
734    static boolean isLinkLocalAddress(byte[] ipaddress) {
735        return ((ipaddress[0] & 0xff) == 0xfe
736                && (ipaddress[1] & 0xc0) == 0x80);
737    }
738
739    /**
740     * Utility routine to check if the InetAddress is a site local address.
741     *
742     * @return a {@code boolean} indicating if the InetAddress is a site local
743     *         address; or false if address is not a site local unicast address.
744     *
745     * @since 1.4
746     */
747    @Override
748    public boolean isSiteLocalAddress() {
749        return holder6.isSiteLocalAddress();
750    }
751
752    /* static version of above */
753    static boolean isSiteLocalAddress(byte[] ipaddress) {
754        return ((ipaddress[0] & 0xff) == 0xfe
755                && (ipaddress[1] & 0xc0) == 0xc0);
756    }
757
758    /**
759     * Utility routine to check if the multicast address has global scope.
760     *
761     * @return a {@code boolean} indicating if the address has is a multicast
762     *         address of global scope, false if it is not of global scope or
763     *         it is not a multicast address
764     *
765     * @since 1.4
766     */
767    @Override
768    public boolean isMCGlobal() {
769        return holder6.isMCGlobal();
770    }
771
772    /**
773     * Utility routine to check if the multicast address has node scope.
774     *
775     * @return a {@code boolean} indicating if the address has is a multicast
776     *         address of node-local scope, false if it is not of node-local
777     *         scope or it is not a multicast address
778     *
779     * @since 1.4
780     */
781    @Override
782    public boolean isMCNodeLocal() {
783        return holder6.isMCNodeLocal();
784    }
785
786    /**
787     * Utility routine to check if the multicast address has link scope.
788     *
789     * @return a {@code boolean} indicating if the address has is a multicast
790     *         address of link-local scope, false if it is not of link-local
791     *         scope or it is not a multicast address
792     *
793     * @since 1.4
794     */
795    @Override
796    public boolean isMCLinkLocal() {
797        return holder6.isMCLinkLocal();
798    }
799
800    /**
801     * Utility routine to check if the multicast address has site scope.
802     *
803     * @return a {@code boolean} indicating if the address has is a multicast
804     *         address of site-local scope, false if it is not  of site-local
805     *         scope or it is not a multicast address
806     *
807     * @since 1.4
808     */
809    @Override
810    public boolean isMCSiteLocal() {
811        return holder6.isMCSiteLocal();
812    }
813
814    /**
815     * Utility routine to check if the multicast address has organization scope.
816     *
817     * @return a {@code boolean} indicating if the address has is a multicast
818     *         address of organization-local scope, false if it is not of
819     *         organization-local scope or it is not a multicast address
820     *
821     * @since 1.4
822     */
823    @Override
824    public boolean isMCOrgLocal() {
825        return holder6.isMCOrgLocal();
826    }
827    /**
828     * Returns the raw IP address of this {@code InetAddress} object. The result
829     * is in network byte order: the highest order byte of the address is in
830     * {@code getAddress()[0]}.
831     *
832     * @return  the raw IP address of this object.
833     */
834    @Override
835    public byte[] getAddress() {
836        return holder6.ipaddress.clone();
837    }
838
839    /**
840     * Returns the numeric scopeId, if this instance is associated with
841     * an interface. If no scoped_id is set, the returned value is zero.
842     *
843     * @return the scopeId, or zero if not set.
844     *
845     * @since 1.5
846     */
847     public int getScopeId() {
848        return holder6.scope_id;
849     }
850
851    /**
852     * Returns the scoped interface, if this instance was created with
853     * with a scoped interface.
854     *
855     * @return the scoped interface, or null if not set.
856     * @since 1.5
857     */
858     public NetworkInterface getScopedInterface() {
859        return holder6.scope_ifname;
860     }
861
862    /**
863     * Returns the IP address string in textual presentation. If the instance
864     * was created specifying a scope identifier then the scope id is appended
865     * to the IP address preceded by a "%" (per-cent) character. This can be
866     * either a numeric value or a string, depending on which was used to create
867     * the instance.
868     *
869     * @return  the raw IP address in a string format.
870     */
871    @Override
872    public String getHostAddress() {
873        // Android-changed: getnameinfo returns smarter representations
874        // return holder6.getHostAddress();
875        return Libcore.os.getnameinfo(this, NI_NUMERICHOST); // Can't throw.
876    }
877
878    /**
879     * Returns a hashcode for this IP address.
880     *
881     * @return  a hash code value for this IP address.
882     */
883    @Override
884    public int hashCode() {
885        return holder6.hashCode();
886    }
887
888    /**
889     * Compares this object against the specified object. The result is {@code
890     * true} if and only if the argument is not {@code null} and it represents
891     * the same IP address as this object.
892     *
893     * <p> Two instances of {@code InetAddress} represent the same IP address
894     * if the length of the byte arrays returned by {@code getAddress} is the
895     * same for both, and each of the array components is the same for the byte
896     * arrays.
897     *
898     * @param   obj   the object to compare against.
899     *
900     * @return  {@code true} if the objects are the same; {@code false} otherwise.
901     *
902     * @see     java.net.InetAddress#getAddress()
903     */
904    @Override
905    public boolean equals(Object obj) {
906        if (obj == null || !(obj instanceof Inet6Address))
907            return false;
908
909        Inet6Address inetAddr = (Inet6Address)obj;
910
911        return holder6.equals(inetAddr.holder6);
912    }
913
914    /**
915     * Utility routine to check if the InetAddress is an
916     * IPv4 compatible IPv6 address.
917     *
918     * @return a {@code boolean} indicating if the InetAddress is an IPv4
919     *         compatible IPv6 address; or false if address is IPv4 address.
920     *
921     * @since 1.4
922     */
923    public boolean isIPv4CompatibleAddress() {
924        return holder6.isIPv4CompatibleAddress();
925    }
926
927    // Utilities
928    private final static int INT16SZ = 2;
929
930    /*
931     * Convert IPv6 binary address into presentation (printable) format.
932     *
933     * @param src a byte array representing the IPv6 numeric address
934     * @return a String representing an IPv6 address in
935     *         textual representation format
936     * @since 1.4
937     */
938    static String numericToTextFormat(byte[] src) {
939        StringBuilder sb = new StringBuilder(39);
940        for (int i = 0; i < (INADDRSZ / INT16SZ); i++) {
941            sb.append(Integer.toHexString(((src[i<<1]<<8) & 0xff00)
942                                          | (src[(i<<1)+1] & 0xff)));
943            if (i < (INADDRSZ / INT16SZ) -1 ) {
944               sb.append(":");
945            }
946        }
947        return sb.toString();
948    }
949}
950