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