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