InetAddress.java revision ca8f5b66c546d8545e41f71b6fb852424c681881
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.FileDescriptor;
21import java.io.IOException;
22import java.io.ObjectInputStream;
23import java.io.ObjectOutputStream;
24import java.io.ObjectStreamException;
25import java.io.ObjectStreamField;
26import java.io.Serializable;
27import java.security.AccessController;
28import java.util.Arrays;
29import java.util.ArrayList;
30import java.util.Comparator;
31import java.util.Enumeration;
32import java.util.StringTokenizer;
33
34import org.apache.harmony.luni.net.NetUtil;
35import org.apache.harmony.luni.platform.INetworkSystem;
36import org.apache.harmony.luni.platform.Platform;
37import org.apache.harmony.luni.util.Inet6Util;
38import org.apache.harmony.luni.util.Msg;
39import org.apache.harmony.luni.util.PriviAction;
40
41/**
42 * The Internet Protocol (IP) address representation class. This class
43 * encapsulates an IP address and provides name and reverse name resolution
44 * functions. The address is stored in network order, but as a signed (rather
45 * than unsigned) integer.
46 */
47public class InetAddress extends Object implements Serializable {
48
49    final static byte[] any_bytes = { 0, 0, 0, 0 };
50
51    final static byte[] localhost_bytes = { 127, 0, 0, 1 };
52
53    static InetAddress ANY = new Inet4Address(any_bytes);
54
55    private final static INetworkSystem NETIMPL = Platform.getNetworkSystem();
56
57    final static InetAddress LOOPBACK = new Inet4Address(localhost_bytes,
58            "localhost"); //$NON-NLS-1$
59
60    private static final String ERRMSG_CONNECTION_REFUSED = "Connection refused"; //$NON-NLS-1$
61
62    private static final long serialVersionUID = 3286316764910316507L;
63
64    // BEGIN android-added
65    /**
66     * default time-to-live for DNS cache entries; 600 seconds == 10 minutes
67     */
68    private static final String DEFAULT_NETADDR_CACHE_TTL_SECS = "600";
69    // END android-added
70
71    String hostName;
72
73    private static class WaitReachable {
74    }
75
76    private transient Object waitReachable = new WaitReachable();
77
78    private boolean reached;
79
80    private int addrCount;
81
82    int family = 2;
83
84    byte[] ipaddress;
85
86    // BEGIN android-removed
87    // // Fill in the JNI id caches
88    // private static native void oneTimeInitialization(boolean supportsIPv6);
89    //
90    // static {
91    //     oneTimeInitialization(true);
92    // }
93    // END android-removed
94
95    /**
96     * Constructs an InetAddress.
97     */
98    InetAddress() {
99        super();
100    }
101
102    /**
103     * Constructs an {@code InetAddress}, representing the {@code address} and
104     * {@code hostName}.
105     *
106     * @param address
107     *            the network address.
108     */
109    InetAddress(byte[] address) {
110        super();
111        this.ipaddress = address;
112    }
113
114    /**
115     * Constructs an {@code InetAddress}, representing the {@code address} and
116     * {@code hostName}.
117     *
118     * @param address
119     *            the network address.
120     */
121    InetAddress(byte[] address, String hostName) {
122        super();
123        this.ipaddress = address;
124        this.hostName = hostName;
125    }
126
127    // BEGIN android-removed
128    // CacheElement cacheElement() {
129    //     return new CacheElement();
130    // }
131    // END android-removed
132
133    /**
134     * Compares this {@code InetAddress} instance against the specified address
135     * in {@code obj}. Two addresses are equal if their address byte arrays have
136     * the same length and if the bytes in the arrays are equal.
137     *
138     * @param obj
139     *            the object to be tested for equality.
140     * @return {@code true} if both objects are equal, {@code false} otherwise.
141     */
142    @Override
143    public boolean equals(Object obj) {
144        // BEGIN android-changed
145        if (!(obj instanceof InetAddress)) {
146            return false;
147        }
148        // END android-changed
149
150        // now check if their byte arrays match...
151        byte[] objIPaddress = ((InetAddress) obj).ipaddress;
152        // BEGIN android-added
153        if (objIPaddress.length != ipaddress.length) {
154            return false;
155        }
156        // END android-added
157        for (int i = 0; i < objIPaddress.length; i++) {
158            if (objIPaddress[i] != this.ipaddress[i]) {
159                return false;
160            }
161        }
162        return true;
163    }
164
165    /**
166     * Returns the IP address represented by this {@code InetAddress} instance
167     * as a byte array. The elements are in network order (the highest order
168     * address byte is in the zeroth element).
169     *
170     * @return the address in form of a byte array.
171     */
172    public byte[] getAddress() {
173        return ipaddress.clone();
174    }
175
176    // BEGIN android-added
177    static final Comparator<byte[]> SHORTEST_FIRST = new Comparator<byte[]>() {
178        public int compare(byte[] a1, byte[] a2) {
179            return a1.length - a2.length;
180        }
181    };
182
183    static final Comparator<byte[]> LONGEST_FIRST = new Comparator<byte[]>() {
184        public int compare(byte[] a1, byte[] a2) {
185            return a2.length - a1.length;
186        }
187    };
188
189    /**
190     * Converts an array of byte arrays representing raw IP addresses of a host
191     * to an array of InetAddress objects, sorting to respect the value of the
192     * system preferIPv6Addresses preference.
193     *
194     * @param rawAddresses the raw addresses to convert.
195     * @param hostName the hostname corresponding to the IP address.
196     * @return the corresponding InetAddresses, appropriately sorted.
197     */
198    static InetAddress[] bytesToInetAddresses(byte[][] rawAddresses,
199            String hostName) {
200        // Sort the raw byte arrays.
201        Comparator<byte[]> comparator = preferIPv6Addresses()
202                ? LONGEST_FIRST : SHORTEST_FIRST;
203        Arrays.sort(rawAddresses, comparator);
204
205        // Convert the byte arrays to InetAddresses.
206        InetAddress[] returnedAddresses = new InetAddress[rawAddresses.length];
207        for (int i = 0; i < rawAddresses.length; i++) {
208            byte[] rawAddress = rawAddresses[i];
209            if (rawAddress.length == 16) {
210                returnedAddresses[i] = new Inet6Address(rawAddress, hostName);
211            } else if (rawAddress.length == 4) {
212                returnedAddresses[i] = new Inet4Address(rawAddress, hostName);
213            } else {
214              // Cannot happen, because the underlying code only returns
215              // addresses that are 4 or 16 bytes long.
216              throw new AssertionError("Impossible address length " +
217                                       rawAddress.length);
218            }
219        }
220        return returnedAddresses;
221    }
222    // END android-added
223
224    /**
225     * Gets all IP addresses associated with the given {@code host} identified
226     * by name or literal IP address. The IP address is resolved by the
227     * configured name service. If the host name is empty or {@code null} an
228     * {@code UnknownHostException} is thrown. If the host name is a literal IP
229     * address string an array with the corresponding single {@code InetAddress}
230     * is returned.
231     *
232     * @param host the hostname or literal IP string to be resolved.
233     * @return the array of addresses associated with the specified host.
234     * @throws UnknownHostException if the address lookup fails.
235     */
236    public static InetAddress[] getAllByName(String host)
237            throws UnknownHostException {
238        // BEGIN android-changed
239        return getAllByNameImpl(host, true);
240        // END android-changed
241    }
242
243    // BEGIN android-added
244    /**
245     * Implementation of getAllByName.
246     *
247     * @param host the hostname or literal IP string to be resolved.
248     * @param returnUnshared requests a result that is modifiable by the caller.
249     * @return the array of addresses associated with the specified host.
250     * @throws UnknownHostException if the address lookup fails.
251     */
252    static InetAddress[] getAllByNameImpl(String host, boolean returnUnshared)
253            throws UnknownHostException {
254        if (host == null || 0 == host.length()) {
255            if (preferIPv6Addresses()) {
256                return new InetAddress[] { Inet6Address.LOOPBACK, LOOPBACK };
257            } else {
258                return new InetAddress[] { LOOPBACK, Inet6Address.LOOPBACK };
259            }
260        }
261
262        // Special-case "0" for legacy IPv4 applications.
263        if (host.equals("0")) { //$NON-NLS-1$
264            return new InetAddress[] { InetAddress.ANY };
265        }
266
267        if (isHostName(host)) {
268            SecurityManager security = System.getSecurityManager();
269            if (security != null) {
270                security.checkConnect(host, -1);
271            }
272            if (returnUnshared) {
273                return lookupHostByName(host).clone();
274            } else {
275                return lookupHostByName(host);
276            }
277        }
278
279        byte[] hBytes = Inet6Util.createByteArrayFromIPAddressString(host);
280        if (hBytes.length == 4) {
281            return (new InetAddress[] { new Inet4Address(hBytes) });
282        } else if (hBytes.length == 16) {
283            return (new InetAddress[] { new Inet6Address(hBytes) });
284        }
285        return (new InetAddress[] { new InetAddress(hBytes) });
286    }
287    // END android-added
288
289    /**
290     * Returns the address of a host according to the given host string name
291     * {@code host}. The host string may be either a machine name or a dotted
292     * string IP address. If the latter, the {@code hostName} field is
293     * determined upon demand. {@code host} can be {@code null} which means that
294     * an address of the loopback interface is returned.
295     *
296     * @param host
297     *            the hostName to be resolved to an address or {@code null}.
298     * @return the {@code InetAddress} instance representing the host.
299     * @throws UnknownHostException
300     *             if the address lookup fails.
301     */
302    public static InetAddress getByName(String host) throws UnknownHostException {
303        return getAllByNameImpl(host, false)[0];
304    }
305
306    /**
307     * Gets the textual representation of this IP address.
308     *
309     * @return the textual representation of this host address in form of a
310     *         dotted string.
311     */
312    public String getHostAddress() {
313        return inetNtoaImpl(bytesToInt(ipaddress, 0));
314    }
315
316    /**
317     * Gets the host name of this IP address. If the IP address could not be
318     * resolved, the textual representation in a dotted-quad-notation is
319     * returned.
320     *
321     * @return the corresponding string name of this IP address.
322     */
323    public String getHostName() {
324        try {
325            if (hostName == null) {
326                int address = 0;
327                if (ipaddress.length == 4) {
328                    address = bytesToInt(ipaddress, 0);
329                    if (address == 0) {
330                        return hostName = inetNtoaImpl(address);
331                    }
332                }
333                hostName = getHostByAddrImpl(ipaddress).hostName;
334                if (hostName.equals("localhost") && ipaddress.length == 4 //$NON-NLS-1$
335                        && address != 0x7f000001) {
336                    return hostName = inetNtoaImpl(address);
337                }
338            }
339        } catch (UnknownHostException e) {
340            return hostName = Inet6Util
341                    .createIPAddrStringFromByteArray(ipaddress);
342        }
343        SecurityManager security = System.getSecurityManager();
344        try {
345            // Only check host names, not addresses
346            if (security != null && isHostName(hostName)) {
347                security.checkConnect(hostName, -1);
348            }
349        } catch (SecurityException e) {
350            return Inet6Util.createIPAddrStringFromByteArray(ipaddress);
351        }
352        return hostName;
353    }
354
355    /**
356     * Gets the fully qualified domain name for the host associated with this IP
357     * address. If a security manager is set, it is checked if the method caller
358     * is allowed to get the hostname. Otherwise, the textual representation in
359     * a dotted-quad-notation is returned.
360     *
361     * @return the fully qualified domain name of this IP address.
362     */
363    public String getCanonicalHostName() {
364        String canonicalName;
365        try {
366            int address = 0;
367            if (ipaddress.length == 4) {
368                address = bytesToInt(ipaddress, 0);
369                if (address == 0) {
370                    return inetNtoaImpl(address);
371                }
372            }
373            canonicalName = getHostByAddrImpl(ipaddress).hostName;
374        } catch (UnknownHostException e) {
375            return Inet6Util.createIPAddrStringFromByteArray(ipaddress);
376        }
377        SecurityManager security = System.getSecurityManager();
378        try {
379            // Only check host names, not addresses
380            if (security != null && isHostName(canonicalName)) {
381                security.checkConnect(canonicalName, -1);
382            }
383        } catch (SecurityException e) {
384            return Inet6Util.createIPAddrStringFromByteArray(ipaddress);
385        }
386        return canonicalName;
387    }
388
389    /**
390     * Gets the local host address if the security policy allows this.
391     * Otherwise, gets the loopback address which allows this machine to be
392     * contacted.
393     *
394     * @return the {@code InetAddress} representing the local host.
395     * @throws UnknownHostException
396     *             if the address lookup fails.
397     */
398    public static InetAddress getLocalHost() throws UnknownHostException {
399        String host = getHostNameImpl();
400        SecurityManager security = System.getSecurityManager();
401        try {
402            if (security != null) {
403                security.checkConnect(host, -1);
404            }
405        } catch (SecurityException e) {
406            return InetAddress.LOOPBACK;
407        }
408        return lookupHostByName(host)[0];
409    }
410
411    /**
412     * Gets the hashcode of the represented IP address.
413     *
414     * @return the appropriate hashcode value.
415     */
416    @Override
417    public int hashCode() {
418        return bytesToInt(ipaddress, 0);
419    }
420
421    /**
422     * Returns whether this address is an IP multicast address or not.
423     *
424     * @return {@code true} if this address is in the multicast group, {@code
425     *         false} otherwise.
426     */
427    public boolean isMulticastAddress() {
428        return ((ipaddress[0] & 255) >>> 4) == 0xE;
429    }
430
431    /**
432     * Resolves a hostname to its IP addresses using a cache for faster lookups.
433     *
434     * @param host the hostname to resolve.
435     * @return the IP addresses of the host.
436     */
437    static synchronized InetAddress[] lookupHostByName(String host)
438            throws UnknownHostException {
439        int ttl = -1;
440
441        // BEGIN android-changed
442        String ttlValue = AccessController
443                .doPrivileged(new PriviAction<String>(
444                        "networkaddress.cache.ttl", DEFAULT_NETADDR_CACHE_TTL_SECS)); //$NON-NLS-1$
445        // END android-changed
446        try {
447            if (ttlValue != null) {
448                ttl = Integer.decode(ttlValue).intValue();
449            }
450        } catch (NumberFormatException e) {
451            // Ignored
452        }
453        CacheElement element = null;
454        // BEGIN android-changed
455        if (ttl == 0) {
456            Cache.clear();
457        } else {
458            element = Cache.get(host);
459            if (element != null && ttl > 0) {
460                long delta = System.nanoTime() - element.nanoTimeAdded;
461                if (delta > secondsToNanos(ttl)) {
462                    element = null;
463                }
464            }
465        }
466        if (element != null) {
467            return element.addresses();
468        }
469        // END android-changed
470
471        // TODO Clean up NegativeCache; there's no need to maintain the failure message
472
473        // now try the negative cache
474        String failedMessage = NegativeCache.getFailedMessage(host);
475        if (failedMessage != null) {
476            throw new UnknownHostException(host);
477        }
478
479        // BEGIN android-changed
480        // TODO: Avoid doing I/O from a static synchronized lock.
481        byte[][] rawAddresses;
482        try {
483            rawAddresses = getallbyname(host, Socket.preferIPv4Stack());
484        } catch (UnknownHostException e) {
485            // put the entry in the negative cache
486            NegativeCache.put(host, e.getMessage());
487            // use host for message to match RI, save the cause for giggles
488            throw (UnknownHostException)new UnknownHostException(host).initCause(e);
489        }
490
491        InetAddress[] addresses = bytesToInetAddresses(rawAddresses, host);
492
493        Cache.add(host, addresses);
494        return addresses;
495        // END android-changed
496    }
497
498    // BEGIN android-added
499    /**
500     * Multiplies value by 1 billion.
501     */
502    private static long secondsToNanos(int ttl) {
503        return (long) ttl * 1000000000;
504    }
505    // END android-added
506
507    // BEGIN android-deleted
508    // static native InetAddress[] getAliasesByNameImpl(String name)
509    //     throws UnknownHostException;
510    // END android-deleted
511
512    // BEGIN android-added
513    /**
514     * Resolves a host name to its IP addresses. Thread safe.
515     */
516    private static native byte[][] getallbyname(String name,
517            boolean preferIPv4Stack) throws UnknownHostException;
518    // END android-added
519
520    /**
521     * Query the IP stack for the host address. The host is in address form.
522     *
523     * @param addr
524     *            the host address to lookup.
525     * @throws UnknownHostException
526     *             if an error occurs during lookup.
527     */
528    // BEGIN android-changed
529    // static native InetAddress getHostByAddrImpl(byte[] addr)
530    //    throws UnknownHostException;
531    static InetAddress getHostByAddrImpl(byte[] addr)
532            throws UnknownHostException {
533        return new InetAddress(addr, gethostbyaddr(addr));
534    }
535
536    /**
537     * Resolves an IP address to a hostname. Thread safe.
538     */
539    private static native String gethostbyaddr(byte[] addr);
540    // END android-changed
541
542    static int inetAddr(String host) throws UnknownHostException {
543        return (host.equals("255.255.255.255")) ? 0xFFFFFFFF //$NON-NLS-1$
544                : inetAddrImpl(host);
545    }
546
547    /**
548     * Convert a string containing an IPv4 Internet Protocol dotted address into
549     * a binary address. Note, the special case of '255.255.255.255' throws an
550     * exception, so this value should not be used as an argument. See also
551     * inetAddr(String).
552     */
553    // BEGIN android-changed
554    // static native int inetAddrImpl(String host) throws UnknownHostException;
555    static int inetAddrImpl(String host) throws UnknownHostException {
556        // TODO Probably not exactly what we want, and also inefficient. Provide native later.
557        try {
558            String[] args = host.split("\\.");
559
560            int a = Integer.parseInt(args[0]) << 24;
561            int b = Integer.parseInt(args[1]) << 16;
562            int c = Integer.parseInt(args[2]) <<  8;
563            int d = Integer.parseInt(args[3])      ;
564
565            return a | b | c | d;
566        } catch (Exception ex) {
567            throw new UnknownHostException(host);
568        }
569    }
570    // END android-changed
571
572    /**
573     * Convert a binary address into a string containing an Ipv4 Internet
574     * Protocol dotted address.
575     */
576    // BEGIN android-changed
577    // static native String inetNtoaImpl(int hipAddr);
578    static String inetNtoaImpl(int hipAddr) {
579        // TODO Inefficient and probably wrong. Provide proper (native?) implementation later.
580        int a = (hipAddr >> 24) & 0xFF;
581        int b = (hipAddr >> 16) & 0xFF;
582        int c = (hipAddr >>  8) & 0xFF;
583        int d = (hipAddr      ) & 0xFF;
584
585        return "" + a + "." + b + "." + c + "." + d;
586    }
587    // END android-changed
588
589    // BEGIN android-removed
590    /**
591     * Query the IP stack for the host address. The host is in string name form.
592     *
593     * @param name
594     *            the host name to lookup
595     * @param preferIPv6Address
596     *            address preference if underlying platform is V4/V6
597     * @return InetAddress the host address
598     * @throws UnknownHostException
599     *             if an error occurs during lookup
600     */
601    // static native InetAddress getHostByNameImpl(String name,
602    //         boolean preferIPv6Address) throws UnknownHostException;
603    // END android-removed
604
605    /**
606     * Gets the host name of the system.
607     *
608     * @return String the system hostname
609     */
610    // BEGIN android-changed
611    static String getHostNameImpl() {
612        // TODO Mapped Harmony to Android native. Get rid of indirection later.
613
614        return gethostname();
615    }
616    static native String gethostname();
617    // END android-changed
618
619    static String getHostNameInternal(String host) throws UnknownHostException {
620        if (host == null || 0 == host.length()) {
621            return InetAddress.LOOPBACK.getHostAddress();
622        }
623        if (isHostName(host)) {
624            return lookupHostByName(host)[0].getHostAddress();
625        }
626        return host;
627    }
628
629    /**
630     * Returns a string containing a concise, human-readable description of this
631     * IP address.
632     *
633     * @return the description, as host/address.
634     */
635    @Override
636    public String toString() {
637        return (hostName == null ? "" : hostName) + "/" + getHostAddress(); //$NON-NLS-1$ //$NON-NLS-2$
638    }
639
640    // BEGIN android-changed
641    // Partly copied from a newer version of harmony
642    static class CacheElement {
643        final long nanoTimeAdded = System.nanoTime();
644
645        CacheElement next;
646        final String hostName;
647        final InetAddress[] addresses;
648
649        CacheElement(String hostName, InetAddress[] addresses) {
650            this.addresses = addresses;
651            this.hostName = hostName;
652        }
653
654        String hostName() {
655            return hostName;
656        }
657
658        InetAddress[] addresses() {
659            return addresses;
660        }
661        // END android-changed
662    }
663
664    static class Cache {
665        private static int maxSize = 5;
666
667        private static int size = 0;
668
669        private static CacheElement head;
670
671        static synchronized void clear() {
672            size = 0;
673            head = null;
674        }
675
676        static synchronized void add(String hostName, InetAddress[] addresses) {
677            CacheElement newElement = new CacheElement(hostName, addresses);
678            if (size < maxSize) {
679                size++;
680            } else {
681                deleteTail();
682            }
683            newElement.next = head; // If the head is null, this does no harm.
684            head = newElement;
685        }
686
687        static synchronized CacheElement get(String name) {
688            CacheElement previous = null;
689            CacheElement current = head;
690            boolean notFound = true;
691            while ((null != current)
692                    && (notFound = !(name.equals(current.hostName())))) {
693                previous = current;
694                current = current.next;
695            }
696            if (notFound) {
697                return null;
698            }
699            moveToHead(current, previous);
700            return current;
701        }
702
703        private synchronized static void deleteTail() {
704            if (0 == size) {
705                return;
706            }
707            if (1 == size) {
708                head = null;
709            }
710
711            CacheElement previous = null;
712            CacheElement current = head;
713            while (null != current.next) {
714                previous = current;
715                current = current.next;
716            }
717            previous.next = null;
718        }
719
720        private synchronized static void moveToHead(CacheElement element,
721                CacheElement elementPredecessor) {
722            if (null == elementPredecessor) {
723                head = element;
724            } else {
725                elementPredecessor.next = element.next;
726                element.next = head;
727                head = element;
728            }
729        }
730    }
731
732    /**
733     * Returns true if the string is a host name, false if it is an IP Address.
734     */
735    private static boolean isHostName(String value) {
736        return !(Inet6Util.isValidIPV4Address(value) || Inet6Util
737                .isValidIP6Address(value));
738    }
739
740    /**
741     * Returns whether this address is a loopback address or not. This
742     * implementation returns always {@code false}. Valid IPv4 loopback
743     * addresses are 127.d.d.d The only valid IPv6 loopback address is ::1.
744     *
745     * @return {@code true} if this instance represents a loopback address,
746     *         {@code false} otherwise.
747     */
748    public boolean isLoopbackAddress() {
749        return false;
750    }
751
752    /**
753     * Returns whether this address is a link-local address or not. This
754     * implementation returns always {@code false}.
755     * <p>
756     * Valid IPv6 link-local addresses are FE80::0 through to
757     * FEBF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF.
758     * <p>
759     * There are no valid IPv4 link-local addresses.
760     *
761     * @return {@code true} if this instance represents a link-local address,
762     *         {@code false} otherwise.
763     */
764    public boolean isLinkLocalAddress() {
765        return false;
766    }
767
768    /**
769     * Returns whether this address is a site-local address or not. This
770     * implementation returns always {@code false}.
771     * <p>
772     * Valid IPv6 site-local addresses are FEC0::0 through to
773     * FEFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF.
774     * <p>
775     * There are no valid IPv4 site-local addresses.
776     *
777     * @return {@code true} if this instance represents a site-local address,
778     *         {@code false} otherwise.
779     */
780    public boolean isSiteLocalAddress() {
781        return false;
782    }
783
784    /**
785     * Returns whether this address is a global multicast address or not. This
786     * implementation returns always {@code false}.
787     * <p>
788     * Valid IPv6 link-global multicast addresses are FFxE:/112 where x is a set
789     * of flags, and the additional 112 bits make up the global multicast
790     * address space.
791     * <p>
792     * Valid IPv4 global multicast addresses are between: 224.0.1.0 to
793     * 238.255.255.255.
794     *
795     * @return {@code true} if this instance represents a global multicast
796     *         address, {@code false} otherwise.
797     */
798    public boolean isMCGlobal() {
799        return false;
800    }
801
802    /**
803     * Returns whether this address is a node-local multicast address or not.
804     * This implementation returns always {@code false}.
805     * <p>
806     * Valid IPv6 node-local multicast addresses are FFx1:/112 where x is a set
807     * of flags, and the additional 112 bits make up the node-local multicast
808     * address space.
809     * <p>
810     * There are no valid IPv4 node-local multicast addresses.
811     *
812     * @return {@code true} if this instance represents a node-local multicast
813     *         address, {@code false} otherwise.
814     */
815    public boolean isMCNodeLocal() {
816        return false;
817    }
818
819    /**
820     * Returns whether this address is a link-local multicast address or not.
821     * This implementation returns always {@code false}.
822     * <p>
823     * Valid IPv6 link-local multicast addresses are FFx2:/112 where x is a set
824     * of flags, and the additional 112 bits make up the link-local multicast
825     * address space.
826     * <p>
827     * Valid IPv4 link-local addresses are between: 224.0.0.0 to 224.0.0.255
828     *
829     * @return {@code true} if this instance represents a link-local multicast
830     *         address, {@code false} otherwise.
831     */
832    public boolean isMCLinkLocal() {
833        return false;
834    }
835
836    /**
837     * Returns whether this address is a site-local multicast address or not.
838     * This implementation returns always {@code false}.
839     * <p>
840     * Valid IPv6 site-local multicast addresses are FFx5:/112 where x is a set
841     * of flags, and the additional 112 bits make up the site-local multicast
842     * address space.
843     * <p>
844     * Valid IPv4 site-local addresses are between: 239.252.0.0 to
845     * 239.255.255.255
846     *
847     * @return {@code true} if this instance represents a site-local multicast
848     *         address, {@code false} otherwise.
849     */
850    public boolean isMCSiteLocal() {
851        return false;
852    }
853
854    /**
855     * Returns whether this address is a organization-local multicast address or
856     * not. This implementation returns always {@code false}.
857     * <p>
858     * Valid IPv6 organization-local multicast addresses are FFx8:/112 where x
859     * is a set of flags, and the additional 112 bits make up the
860     * organization-local multicast address space.
861     * <p>
862     * Valid IPv4 organization-local addresses are between: 239.192.0.0 to
863     * 239.251.255.255
864     *
865     * @return {@code true} if this instance represents a organization-local
866     *         multicast address, {@code false} otherwise.
867     */
868    public boolean isMCOrgLocal() {
869        return false;
870    }
871
872    /**
873     * Returns whether this is a wildcard address or not. This implementation
874     * returns always {@code false}.
875     *
876     * @return {@code true} if this instance represents a wildcard address,
877     *         {@code false} otherwise.
878     */
879    public boolean isAnyLocalAddress() {
880        return false;
881    }
882
883    /**
884     * Tries to reach this {@code InetAddress}. This method first tries to use
885     * ICMP <i>(ICMP ECHO REQUEST)</i>. When first step fails, a TCP connection
886     * on port 7 (Echo) of the remote host is established.
887     *
888     * @param timeout
889     *            timeout in milliseconds before the test fails if no connection
890     *            could be established.
891     * @return {@code true} if this address is reachable, {@code false}
892     *         otherwise.
893     * @throws IOException
894     *             if an error occurs during an I/O operation.
895     * @throws IllegalArgumentException
896     *             if timeout is less than zero.
897     */
898    public boolean isReachable(int timeout) throws IOException {
899        return isReachable(null, 0, timeout);
900    }
901
902    /**
903     * Tries to reach this {@code InetAddress}. This method first tries to use
904     * ICMP <i>(ICMP ECHO REQUEST)</i>. When first step fails, a TCP connection
905     * on port 7 (Echo) of the remote host is established.
906     *
907     * @param netif
908     *            the network interface on which to connection should be
909     *            established.
910     * @param ttl
911     *            the maximum count of hops (time-to-live).
912     * @param timeout
913     *            timeout in milliseconds before the test fails if no connection
914     *            could be established.
915     * @return {@code true} if this address is reachable, {@code false}
916     *         otherwise.
917     * @throws IOException
918     *             if an error occurs during an I/O operation.
919     * @throws IllegalArgumentException
920     *             if ttl or timeout is less than zero.
921     */
922    public boolean isReachable(NetworkInterface netif, final int ttl,
923            final int timeout) throws IOException {
924        if (0 > ttl || 0 > timeout) {
925            throw new IllegalArgumentException(Msg.getString("K0051")); //$NON-NLS-1$
926        }
927        boolean reachable = false;
928        if (null == netif) {
929            // network interface is null, binds to no address
930            // BEGIN android-changed
931            // reachable = NETIMPL.isReachableByICMP(this, null, ttl, timeout);
932            // if (!reachable) {
933                reachable = isReachableByTCP(this, null, timeout);
934            // }
935            // END android-changed
936        } else {
937            // Not Bind to any address
938            if (null == netif.addresses) {
939                return false;
940            }
941            // binds to all address on this NetworkInterface, tries ICMP ping
942            // first
943            // BEGIN android-changed
944            // reachable = isReachableByICMPUseMultiThread(netif, ttl, timeout);
945            // if (!reachable) {
946                // tries TCP echo if ICMP ping fails
947                reachable = isReachableByMultiThread(netif, ttl, timeout);
948            // }
949            // END adnroid-changed
950        }
951        return reachable;
952    }
953
954    /*
955     * Uses multi-Thread to try if isReachable, returns true if any of threads
956     * returns in time
957     */
958    // BEGIN android-changed
959    private boolean isReachableByMultiThread(NetworkInterface netif,
960            final int ttl, final int timeout)
961    // END android-changed
962            throws IOException {
963        if (null == netif.addresses) {
964            return false;
965        }
966        Enumeration<InetAddress> addresses = netif.getInetAddresses();
967        reached = false;
968        addrCount = netif.addresses.length;
969        boolean needWait = false;
970        while (addresses.hasMoreElements()) {
971            final InetAddress addr = addresses.nextElement();
972
973            // loopback interface can only reach to local addresses
974            if (addr.isLoopbackAddress()) {
975                Enumeration<NetworkInterface> NetworkInterfaces = NetworkInterface
976                        .getNetworkInterfaces();
977                while (NetworkInterfaces.hasMoreElements()) {
978                    NetworkInterface networkInterface = NetworkInterfaces
979                            .nextElement();
980                    Enumeration<InetAddress> localAddresses = networkInterface
981                            .getInetAddresses();
982                    while (localAddresses.hasMoreElements()) {
983                        if (InetAddress.this.equals(localAddresses
984                                .nextElement())) {
985                            return true;
986                        }
987                    }
988                }
989
990                synchronized (waitReachable) {
991                    addrCount--;
992
993                    if (addrCount == 0) {
994                        // if count equals zero, all thread
995                        // expired,notifies main thread
996                        waitReachable.notifyAll();
997                    }
998                }
999                continue;
1000            }
1001
1002            needWait = true;
1003            new Thread() {
1004                @Override
1005                public void run() {
1006                    boolean threadReached = false;
1007                    // BEGIN android-changed
1008                    // if isICMP, tries ICMP ping, else TCP echo
1009                    // if (isICMP) {
1010                    //     threadReached = NETIMPL.isReachableByICMP(
1011                    //             InetAddress.this, addr, ttl, timeout);
1012                    // } else {
1013                        try {
1014                            threadReached = isReachableByTCP(addr,
1015                                    InetAddress.this, timeout);
1016                        } catch (IOException e) {
1017                            // do nothing
1018                        }
1019                    // }
1020                    // END android-changed
1021
1022                    synchronized (waitReachable) {
1023                        if (threadReached) {
1024                            // if thread reached this address, sets reached to
1025                            // true and notifies main thread
1026                            reached = true;
1027                            waitReachable.notifyAll();
1028                        } else {
1029                            addrCount--;
1030                            if (0 == addrCount) {
1031                                // if count equals zero, all thread
1032                                // expired,notifies main thread
1033                                waitReachable.notifyAll();
1034                            }
1035                        }
1036                    }
1037                }
1038            }.start();
1039        }
1040
1041        if (needWait) {
1042            synchronized (waitReachable) {
1043                try {
1044                    while (!reached && (addrCount != 0)) {
1045                        // wait for notification
1046                        waitReachable.wait(1000);
1047                    }
1048                } catch (InterruptedException e) {
1049                    // do nothing
1050                }
1051                return reached;
1052            }
1053        }
1054
1055        return false;
1056    }
1057
1058    // BEGIN android-removed
1059    // private boolean isReachableByICMPUseMultiThread(NetworkInterface netif,
1060    //         int ttl, int timeout) throws IOException {
1061    //     return isReachableByMultiThread(netif, ttl, timeout, true);
1062    // }
1063    //
1064    // private boolean isReachableByTCPUseMultiThread(NetworkInterface netif,
1065    //         int ttl, int timeout) throws IOException {
1066    //     return isReachableByMultiThread(netif, ttl, timeout, false);
1067    // }
1068    // END android-removed
1069
1070    private boolean isReachableByTCP(InetAddress dest, InetAddress source,
1071            int timeout) throws IOException {
1072        FileDescriptor fd = new FileDescriptor();
1073        // define traffic only for parameter
1074        int traffic = 0;
1075        boolean reached = false;
1076        NETIMPL.createStreamSocket(fd, NetUtil.preferIPv4Stack());
1077        try {
1078            if (null != source) {
1079                NETIMPL.bind(fd, source, 0);
1080            }
1081            NETIMPL.connectStreamWithTimeoutSocket(fd, 7, timeout, traffic,
1082                    dest);
1083            reached = true;
1084        } catch (IOException e) {
1085            if (ERRMSG_CONNECTION_REFUSED.equals(e.getMessage())) {
1086                // Connection refused means the IP is reachable
1087                reached = true;
1088            }
1089        }
1090
1091        NETIMPL.socketClose(fd);
1092
1093        return reached;
1094    }
1095
1096    /**
1097     * Returns the {@code InetAddress} corresponding to the array of bytes. In
1098     * the case of an IPv4 address there must be exactly 4 bytes and for IPv6
1099     * exactly 16 bytes. If not, an {@code UnknownHostException} is thrown.
1100     * <p>
1101     * The IP address is not validated by a name service.
1102     * <p>
1103     * The high order byte is {@code ipAddress[0]}.
1104     *
1105     * @param ipAddress
1106     *            is either a 4 (IPv4) or 16 (IPv6) byte long array.
1107     * @return an {@code InetAddress} instance representing the given IP address
1108     *         {@code ipAddress}.
1109     * @throws UnknownHostException
1110     *             if the given byte array has no valid length.
1111     */
1112    public static InetAddress getByAddress(byte[] ipAddress)
1113            throws UnknownHostException {
1114        // simply call the method by the same name specifying the default scope
1115        // id of 0
1116        return getByAddress(ipAddress, 0);
1117    }
1118
1119    /**
1120     * Returns the {@code InetAddress} corresponding to the array of bytes. In
1121     * the case of an IPv4 address there must be exactly 4 bytes and for IPv6
1122     * exactly 16 bytes. If not, an {@code UnknownHostException} is thrown. The
1123     * IP address is not validated by a name service. The high order byte is
1124     * {@code ipAddress[0]}.
1125     *
1126     * @param ipAddress
1127     *            either a 4 (IPv4) or 16 (IPv6) byte array.
1128     * @param scope_id
1129     *            the scope id for an IPV6 scoped address. If not a scoped
1130     *            address just pass in 0.
1131     * @return the InetAddress
1132     * @throws UnknownHostException
1133     */
1134    static InetAddress getByAddress(byte[] ipAddress, int scope_id)
1135            throws UnknownHostException {
1136        byte[] copy_address;
1137        if (ipAddress != null && ipAddress.length == 4) {
1138            copy_address = new byte[4];
1139            for (int i = 0; i < 4; i++) {
1140                copy_address[i] = ipAddress[i];
1141            }
1142            return new Inet4Address(copy_address);
1143        }
1144
1145        if (ipAddress != null && ipAddress.length == 16) {
1146            // First check to see if the address is an IPv6-mapped
1147            // IPv4 address. If it is, then we can make it a IPv4
1148            // address, otherwise, we'll create an IPv6 address.
1149            if (isIPv4MappedAddress(ipAddress)) {
1150                copy_address = new byte[4];
1151                for (int i = 0; i < 4; i++) {
1152                    copy_address[i] = ipAddress[12 + i];
1153                }
1154                return new Inet4Address(copy_address);
1155            }
1156            copy_address = ipAddress.clone();
1157            return new Inet6Address(copy_address, scope_id);
1158        }
1159
1160        // K0339=Invalid IP Address is neither 4 or 16 bytes
1161        throw new UnknownHostException(Msg.getString("K0339")); //$NON-NLS-1$
1162    }
1163
1164    private static boolean isIPv4MappedAddress(byte ipAddress[]) {
1165        // Check if the address matches ::FFFF:d.d.d.d
1166        // The first 10 bytes are 0. The next to are -1 (FF).
1167        // The last 4 bytes are varied.
1168        for (int i = 0; i < 10; i++) {
1169            if (ipAddress[i] != 0) {
1170                return false;
1171            }
1172        }
1173
1174        if (ipAddress[10] != -1 || ipAddress[11] != -1) {
1175            return false;
1176        }
1177
1178        return true;
1179    }
1180
1181    /**
1182     * Returns the {@code InetAddress} corresponding to the array of bytes, and
1183     * the given hostname. In the case of an IPv4 address there must be exactly
1184     * 4 bytes and for IPv6 exactly 16 bytes. If not, an {@code
1185     * UnknownHostException} will be thrown.
1186     * <p>
1187     * The host name and IP address are not validated.
1188     * <p>
1189     * The hostname either be a machine alias or a valid IPv6 or IPv4 address
1190     * format.
1191     * <p>
1192     * The high order byte is {@code ipAddress[0]}.
1193     *
1194     * @param hostName
1195     *            the string representation of hostname or IP address.
1196     * @param ipAddress
1197     *            either a 4 (IPv4) or 16 (IPv6) byte long array.
1198     * @return an {@code InetAddress} instance representing the given IP address
1199     *         and hostname.
1200     * @throws UnknownHostException
1201     *             if the given byte array has no valid length.
1202     */
1203    public static InetAddress getByAddress(String hostName, byte[] ipAddress)
1204            throws UnknownHostException {
1205        // just call the method by the same name passing in a default scope id
1206        // of 0
1207        return getByAddressInternal(hostName, ipAddress, 0);
1208    }
1209
1210    /**
1211     * Returns the {@code InetAddress} corresponding to the array of bytes, and
1212     * the given hostname. In the case of an IPv4 address there must be exactly
1213     * 4 bytes and for IPv6 exactly 16 bytes. If not, an {@code
1214     * UnknownHostException} is thrown. The host name and IP address are not
1215     * validated. The hostname either be a machine alias or a valid IPv6 or IPv4
1216     * address format. The high order byte is {@code ipAddress[0]}.
1217     *
1218     * @param hostName
1219     *            string representation of hostname or IP address.
1220     * @param ipAddress
1221     *            either a 4 (IPv4) or 16 (IPv6) byte array.
1222     * @param scope_id
1223     *            the scope id for a scoped address. If not a scoped address
1224     *            just pass in 0.
1225     * @return the InetAddress
1226     * @throws UnknownHostException
1227     */
1228    static InetAddress getByAddressInternal(String hostName, byte[] ipAddress,
1229            int scope_id) throws UnknownHostException {
1230        byte[] copy_address;
1231        if (ipAddress != null && ipAddress.length == 4) {
1232            copy_address = new byte[4];
1233            for (int i = 0; i < 4; i++) {
1234                copy_address[i] = ipAddress[i];
1235            }
1236            return new Inet4Address(ipAddress, hostName);
1237        }
1238
1239        if (ipAddress != null && ipAddress.length == 16) {
1240            // First check to see if the address is an IPv6-mapped
1241            // IPv4 address. If it is, then we can make it a IPv4
1242            // address, otherwise, we'll create an IPv6 address.
1243            if (isIPv4MappedAddress(ipAddress)) {
1244                copy_address = new byte[4];
1245                for (int i = 0; i < 4; i++) {
1246                    copy_address[i] = ipAddress[12 + i];
1247                }
1248                return new Inet4Address(ipAddress, hostName);
1249            }
1250
1251            copy_address = new byte[16];
1252            for (int i = 0; i < 16; i++) {
1253                copy_address[i] = ipAddress[i];
1254            }
1255
1256            return new Inet6Address(ipAddress, hostName, scope_id);
1257        }
1258
1259        throw new UnknownHostException(Msg.getString("K0332", hostName)); //$NON-NLS-1$
1260    }
1261
1262    /**
1263     * Takes the integer and chops it into 4 bytes, putting it into the byte
1264     * array starting with the high order byte at the index start. This method
1265     * makes no checks on the validity of the parameters.
1266     */
1267    static void intToBytes(int value, byte bytes[], int start) {
1268        // Shift the int so the current byte is right-most
1269        // Use a byte mask of 255 to single out the last byte.
1270        bytes[start] = (byte) ((value >> 24) & 255);
1271        bytes[start + 1] = (byte) ((value >> 16) & 255);
1272        bytes[start + 2] = (byte) ((value >> 8) & 255);
1273        bytes[start + 3] = (byte) (value & 255);
1274    }
1275
1276    /**
1277     * Takes the byte array and creates an integer out of four bytes starting at
1278     * start as the high-order byte. This method makes no checks on the validity
1279     * of the parameters.
1280     */
1281    static int bytesToInt(byte bytes[], int start) {
1282        // First mask the byte with 255, as when a negative
1283        // signed byte converts to an integer, it has bits
1284        // on in the first 3 bytes, we are only concerned
1285        // about the right-most 8 bits.
1286        // Then shift the rightmost byte to align with its
1287        // position in the integer.
1288        int value = ((bytes[start + 3] & 255))
1289                | ((bytes[start + 2] & 255) << 8)
1290                | ((bytes[start + 1] & 255) << 16)
1291                | ((bytes[start] & 255) << 24);
1292        return value;
1293    }
1294
1295    /**
1296     * Creates an InetAddress based on the {@code ipAddressString}. No error
1297     * handling is performed here.
1298     */
1299    static InetAddress createHostNameFromIPAddress(String ipAddressString)
1300            throws UnknownHostException {
1301
1302        InetAddress address = null;
1303
1304        if (Inet6Util.isValidIPV4Address(ipAddressString)) {
1305            byte[] byteAddress = new byte[4];
1306            String[] parts = ipAddressString.split("\\."); //$NON-NLS-1$
1307            int length = parts.length;
1308            if (length == 1) {
1309                long value = Long.parseLong(parts[0]);
1310                for (int i = 0; i < 4; i++) {
1311                    byteAddress[i] = (byte) (value >> ((3 - i) * 8));
1312                }
1313            } else {
1314                for (int i = 0; i < length; i++) {
1315                    byteAddress[i] = (byte) Integer.parseInt(parts[i]);
1316                }
1317            }
1318
1319            // adjust for 2/3 parts address
1320            if (length == 2) {
1321                byteAddress[3] = byteAddress[1];
1322                byteAddress[1] = 0;
1323            }
1324            if (length == 3) {
1325                byteAddress[3] = byteAddress[2];
1326                byteAddress[2] = 0;
1327            }
1328
1329            address = new Inet4Address(byteAddress);
1330        } else { // otherwise it must be ipv6
1331
1332            if (ipAddressString.charAt(0) == '[') {
1333                ipAddressString = ipAddressString.substring(1, ipAddressString
1334                        .length() - 1);
1335            }
1336
1337            StringTokenizer tokenizer = new StringTokenizer(ipAddressString,
1338                    ":.%", true); //$NON-NLS-1$
1339            ArrayList<String> hexStrings = new ArrayList<String>();
1340            ArrayList<String> decStrings = new ArrayList<String>();
1341            String scopeString = null;
1342            String token = ""; //$NON-NLS-1$
1343            String prevToken = ""; //$NON-NLS-1$
1344            String prevPrevToken = ""; //$NON-NLS-1$
1345            int doubleColonIndex = -1; // If a double colon exists, we need to
1346            // insert 0s.
1347
1348            // Go through the tokens, including the separators ':' and '.'
1349            // When we hit a : or . the previous token will be added to either
1350            // the hex list or decimal list. In the case where we hit a ::
1351            // we will save the index of the hexStrings so we can add zeros
1352            // in to fill out the string
1353            while (tokenizer.hasMoreTokens()) {
1354                prevPrevToken = prevToken;
1355                prevToken = token;
1356                token = tokenizer.nextToken();
1357
1358                if (token.equals(":")) { //$NON-NLS-1$
1359                    if (prevToken.equals(":")) { //$NON-NLS-1$
1360                        doubleColonIndex = hexStrings.size();
1361                    } else if (!prevToken.equals("")) { //$NON-NLS-1$
1362                        hexStrings.add(prevToken);
1363                    }
1364                } else if (token.equals(".")) { //$NON-NLS-1$
1365                    decStrings.add(prevToken);
1366                } else if (token.equals("%")) { //$NON-NLS-1$
1367                    // add the last word before the % properly
1368                    if (!prevToken.equals(":") && !prevToken.equals(".")) { //$NON-NLS-1$ //$NON-NLS-2$
1369                        if (prevPrevToken.equals(":")) { //$NON-NLS-1$
1370                            hexStrings.add(prevToken);
1371                        } else if (prevPrevToken.equals(".")) { //$NON-NLS-1$
1372                            decStrings.add(prevToken);
1373                        }
1374                    }
1375
1376                    // the rest should be the scope string
1377                    scopeString = tokenizer.nextToken();
1378                    while (tokenizer.hasMoreTokens()) {
1379                        scopeString = scopeString + tokenizer.nextToken();
1380                    }
1381                }
1382            }
1383
1384            if (prevToken.equals(":")) { //$NON-NLS-1$
1385                if (token.equals(":")) { //$NON-NLS-1$
1386                    doubleColonIndex = hexStrings.size();
1387                } else {
1388                    hexStrings.add(token);
1389                }
1390            } else if (prevToken.equals(".")) { //$NON-NLS-1$
1391                decStrings.add(token);
1392            }
1393
1394            // figure out how many hexStrings we should have
1395            // also check if it is a IPv4 address
1396            int hexStringsLength = 8;
1397
1398            // If we have an IPv4 address tagged on at the end, subtract
1399            // 4 bytes, or 2 hex words from the total
1400            if (decStrings.size() > 0) {
1401                hexStringsLength -= 2;
1402            }
1403
1404            // if we hit a double Colon add the appropriate hex strings
1405            if (doubleColonIndex != -1) {
1406                int numberToInsert = hexStringsLength - hexStrings.size();
1407                for (int i = 0; i < numberToInsert; i++) {
1408                    hexStrings.add(doubleColonIndex, "0"); //$NON-NLS-1$
1409                }
1410            }
1411
1412            byte ipByteArray[] = new byte[16];
1413
1414            // Finally convert these strings to bytes...
1415            for (int i = 0; i < hexStrings.size(); i++) {
1416                Inet6Util.convertToBytes(hexStrings.get(i), ipByteArray, i * 2);
1417            }
1418
1419            // Now if there are any decimal values, we know where they go...
1420            for (int i = 0; i < decStrings.size(); i++) {
1421                ipByteArray[i + 12] = (byte) (Integer.parseInt(decStrings
1422                        .get(i)) & 255);
1423            }
1424
1425            // now check to see if this guy is actually and IPv4 address
1426            // an ipV4 address is ::FFFF:d.d.d.d
1427            boolean ipV4 = true;
1428            for (int i = 0; i < 10; i++) {
1429                if (ipByteArray[i] != 0) {
1430                    ipV4 = false;
1431                    break;
1432                }
1433            }
1434
1435            if (ipByteArray[10] != -1 || ipByteArray[11] != -1) {
1436                ipV4 = false;
1437            }
1438
1439            if (ipV4) {
1440                byte ipv4ByteArray[] = new byte[4];
1441                for (int i = 0; i < 4; i++) {
1442                    ipv4ByteArray[i] = ipByteArray[i + 12];
1443                }
1444                address = InetAddress.getByAddress(ipv4ByteArray);
1445            } else {
1446                int scopeId = 0;
1447                if (scopeString != null) {
1448                    try {
1449                        scopeId = Integer.parseInt(scopeString);
1450                    } catch (Exception e) {
1451                        // this should not occur as we should not get into this
1452                        // function unless the address is in a valid format
1453                    }
1454                }
1455                address = InetAddress.getByAddress(ipByteArray, scopeId);
1456            }
1457        }
1458
1459        return address;
1460    }
1461
1462    static boolean preferIPv6Addresses() {
1463        String result = AccessController.doPrivileged(new PriviAction<String>(
1464                "java.net.preferIPv6Addresses")); //$NON-NLS-1$
1465        return "true".equals(result); //$NON-NLS-1$
1466    }
1467
1468    private static final ObjectStreamField[] serialPersistentFields = {
1469            new ObjectStreamField("address", Integer.TYPE), //$NON-NLS-1$
1470            new ObjectStreamField("family", Integer.TYPE), //$NON-NLS-1$
1471            new ObjectStreamField("hostName", String.class) }; //$NON-NLS-1$
1472
1473    private void writeObject(ObjectOutputStream stream) throws IOException {
1474        ObjectOutputStream.PutField fields = stream.putFields();
1475        if (ipaddress == null) {
1476            fields.put("address", 0); //$NON-NLS-1$
1477        } else {
1478            fields.put("address", bytesToInt(ipaddress, 0)); //$NON-NLS-1$
1479        }
1480        fields.put("family", family); //$NON-NLS-1$
1481        fields.put("hostName", hostName); //$NON-NLS-1$
1482
1483        stream.writeFields();
1484    }
1485
1486    private void readObject(ObjectInputStream stream) throws IOException,
1487            ClassNotFoundException {
1488        ObjectInputStream.GetField fields = stream.readFields();
1489        int addr = fields.get("address", 0); //$NON-NLS-1$
1490        ipaddress = new byte[4];
1491        intToBytes(addr, ipaddress, 0);
1492        hostName = (String) fields.get("hostName", null); //$NON-NLS-1$
1493        family = fields.get("family", 2); //$NON-NLS-1$
1494    }
1495
1496    private Object readResolve() throws ObjectStreamException {
1497        return new Inet4Address(ipaddress, hostName);
1498    }
1499}
1500