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