0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package java.net;
0019:
0020: import java.io.FileDescriptor;
0021: import java.io.IOException;
0022: import java.io.ObjectInputStream;
0023: import java.io.ObjectOutputStream;
0024: import java.io.ObjectStreamException;
0025: import java.io.ObjectStreamField;
0026: import java.io.Serializable;
0027: import java.security.AccessController;
0028: import java.util.ArrayList;
0029: import java.util.Enumeration;
0030: import java.util.StringTokenizer;
0031:
0032: import org.apache.harmony.luni.net.NetUtil;
0033: import org.apache.harmony.luni.platform.INetworkSystem;
0034: import org.apache.harmony.luni.platform.Platform;
0035: import org.apache.harmony.luni.util.Inet6Util;
0036: import org.apache.harmony.luni.util.Msg;
0037: import org.apache.harmony.luni.util.PriviAction;
0038:
0039: /**
0040: * The Internet Protocol (IP) address class. This class encapsulates an IP
0041: * address and provides name and reverse name resolution functions. The address
0042: * is stored in network order, but as a signed (rather than unsigned) integer.
0043: */
0044: public class InetAddress extends Object implements Serializable {
0045:
0046: final static byte[] any_bytes = { 0, 0, 0, 0 };
0047:
0048: final static byte[] localhost_bytes = { 127, 0, 0, 1 };
0049:
0050: static InetAddress ANY = new Inet4Address(any_bytes);
0051:
0052: private final static INetworkSystem NETIMPL = Platform
0053: .getNetworkSystem();
0054:
0055: final static InetAddress LOOPBACK = new Inet4Address(
0056: localhost_bytes, "localhost"); //$NON-NLS-1$
0057:
0058: private static final String ERRMSG_CONNECTION_REFUSED = "Connection refused"; //$NON-NLS-1$
0059:
0060: private static final long serialVersionUID = 3286316764910316507L;
0061:
0062: String hostName;
0063:
0064: private static class WaitReachable {
0065: }
0066:
0067: private transient Object waitReachable = new WaitReachable();
0068:
0069: private boolean reached;
0070:
0071: private int addrCount;
0072:
0073: int family = 2;
0074:
0075: byte[] ipaddress;
0076:
0077: // Fill in the JNI id caches
0078: private static native void oneTimeInitialization(
0079: boolean supportsIPv6);
0080:
0081: static {
0082: oneTimeInitialization(true);
0083: }
0084:
0085: /**
0086: * Constructs an InetAddress.
0087: */
0088: InetAddress() {
0089: super ();
0090: }
0091:
0092: /**
0093: * Constructs an InetAddress, representing the <code>address</code> and
0094: * <code>hostName</code>.
0095: *
0096: * @param address
0097: * network address
0098: */
0099: InetAddress(byte[] address) {
0100: super ();
0101: this .ipaddress = address;
0102: }
0103:
0104: /**
0105: * Constructs an InetAddress, representing the <code>address</code> and
0106: * <code>hostName</code>.
0107: *
0108: * @param address
0109: * network address
0110: */
0111: InetAddress(byte[] address, String hostName) {
0112: super ();
0113: this .ipaddress = address;
0114: this .hostName = hostName;
0115: }
0116:
0117: CacheElement cacheElement() {
0118: return new CacheElement();
0119: }
0120:
0121: /**
0122: * Compares this <code>InetAddress</code> against the specified object.
0123: *
0124: * @param obj
0125: * the object to be tested for equality
0126: * @return boolean true, if the objects are equal
0127: */
0128: @Override
0129: public boolean equals(Object obj) {
0130: if (obj == null) {
0131: return false;
0132: }
0133: if (obj.getClass() != this .getClass()) {
0134: return false;
0135: }
0136:
0137: // now check if their byte arrays match...
0138: byte[] objIPaddress = ((InetAddress) obj).ipaddress;
0139: for (int i = 0; i < objIPaddress.length; i++) {
0140: if (objIPaddress[i] != this .ipaddress[i]) {
0141: return false;
0142: }
0143: }
0144: return true;
0145: }
0146:
0147: /**
0148: * Returns the IP address of this <code>InetAddress</code> as an array.
0149: * The elements are in network order (the highest order address byte is in
0150: * the zero-th element).
0151: *
0152: * @return byte[] the address as a byte array
0153: */
0154: public byte[] getAddress() {
0155: return ipaddress.clone();
0156: }
0157:
0158: /**
0159: * Answer the IP addresses of a named host. The host name may either be a
0160: * machine name or a dotted string IP address. If the host name is empty or
0161: * null, an UnknownHostException is thrown. If the host name is a dotted IP
0162: * string, an array with the corresponding single InetAddress is returned.
0163: *
0164: * @param host
0165: * the hostName to be resolved to an address
0166: *
0167: * @return InetAddress[] an array of addresses for the host
0168: * @throws UnknownHostException
0169: * if the address lookup fails
0170: */
0171: public static InetAddress[] getAllByName(String host)
0172: throws UnknownHostException {
0173: if (host == null || 0 == host.length()) {
0174: return new InetAddress[] { preferIPv6Addresses() ? Inet6Address.LOOPBACK
0175: : LOOPBACK };
0176: }
0177:
0178: if (isHostName(host)) {
0179: SecurityManager security = System.getSecurityManager();
0180: if (security != null) {
0181: security.checkConnect(host, -1);
0182: }
0183: if (Socket.preferIPv4Stack()) {
0184: return getAliasesByNameImpl(host);
0185: }
0186:
0187: // ok we may have to re-order to make sure the
0188: // preferIPv6Addresses is respected
0189: InetAddress[] returnedAddresses = getAliasesByNameImpl(host);
0190: InetAddress[] orderedAddresses = null;
0191: if (returnedAddresses != null) {
0192: orderedAddresses = new InetAddress[returnedAddresses.length];
0193: int curPosition = 0;
0194: if (InetAddress.preferIPv6Addresses()) {
0195: for (int i = 0; i < returnedAddresses.length; i++) {
0196: if (returnedAddresses[i] instanceof Inet6Address) {
0197: orderedAddresses[curPosition] = returnedAddresses[i];
0198: curPosition++;
0199: }
0200: }
0201: for (int i = 0; i < returnedAddresses.length; i++) {
0202: if (returnedAddresses[i] instanceof Inet4Address) {
0203: orderedAddresses[curPosition] = returnedAddresses[i];
0204: curPosition++;
0205: }
0206: }
0207: } else {
0208: for (int i = 0; i < returnedAddresses.length; i++) {
0209: if (returnedAddresses[i] instanceof Inet4Address) {
0210: orderedAddresses[curPosition] = returnedAddresses[i];
0211: curPosition++;
0212: }
0213: }
0214: for (int i = 0; i < returnedAddresses.length; i++) {
0215: if (returnedAddresses[i] instanceof Inet6Address) {
0216: orderedAddresses[curPosition] = returnedAddresses[i];
0217: curPosition++;
0218: }
0219: }
0220: }
0221: }
0222: return orderedAddresses;
0223: }
0224:
0225: byte[] hBytes = Inet6Util
0226: .createByteArrayFromIPAddressString(host);
0227: return (new InetAddress[] { new InetAddress(hBytes) });
0228: }
0229:
0230: /**
0231: * Answers the address of a host, given a host string name. The host string
0232: * may be either a machine name or a dotted string IP address. If the
0233: * latter, the hostName field will be determined upon demand.
0234: *
0235: * @param host
0236: * the hostName to be resolved to an address
0237: * @return InetAddress the InetAddress representing the host
0238: *
0239: * @throws UnknownHostException
0240: * if the address lookup fails
0241: */
0242: public static InetAddress getByName(String host)
0243: throws UnknownHostException {
0244: if (host == null || 0 == host.length()) {
0245: return InetAddress.LOOPBACK;
0246: }
0247: if (host.equals("0")) { //$NON-NLS-1$
0248: return InetAddress.ANY;
0249: }
0250:
0251: if (isHostName(host)) {
0252: SecurityManager security = System.getSecurityManager();
0253: if (security != null) {
0254: security.checkConnect(host, -1);
0255: }
0256: return lookupHostByName(host);
0257: }
0258:
0259: return createHostNameFromIPAddress(host);
0260: }
0261:
0262: /**
0263: * Answer the dotted string IP address representing this address.
0264: *
0265: * @return String the corresponding dotted string IP address
0266: */
0267: public String getHostAddress() {
0268: return inetNtoaImpl(bytesToInt(ipaddress, 0));
0269: }
0270:
0271: /**
0272: * Answer the host name.
0273: *
0274: * @return String the corresponding string name
0275: */
0276: public String getHostName() {
0277: try {
0278: if (hostName == null) {
0279: int address = 0;
0280: if (ipaddress.length == 4) {
0281: address = bytesToInt(ipaddress, 0);
0282: if (address == 0) {
0283: return hostName = inetNtoaImpl(address);
0284: }
0285: }
0286: hostName = getHostByAddrImpl(ipaddress).hostName;
0287: if (hostName.equals("localhost") && ipaddress.length == 4 //$NON-NLS-1$
0288: && address != 0x7f000001) {
0289: return hostName = inetNtoaImpl(address);
0290: }
0291: }
0292: } catch (UnknownHostException e) {
0293: return hostName = Inet6Util
0294: .createIPAddrStringFromByteArray(ipaddress);
0295: }
0296: SecurityManager security = System.getSecurityManager();
0297: try {
0298: // Only check host names, not addresses
0299: if (security != null && isHostName(hostName)) {
0300: security.checkConnect(hostName, -1);
0301: }
0302: } catch (SecurityException e) {
0303: return Inet6Util.createIPAddrStringFromByteArray(ipaddress);
0304: }
0305: return hostName;
0306: }
0307:
0308: /**
0309: * Answers canonical name for the host associated with the internet address
0310: *
0311: * @return String string containing the host name
0312: */
0313: public String getCanonicalHostName() {
0314: String canonicalName;
0315: try {
0316: int address = 0;
0317: if (ipaddress.length == 4) {
0318: address = bytesToInt(ipaddress, 0);
0319: if (address == 0) {
0320: return inetNtoaImpl(address);
0321: }
0322: }
0323: canonicalName = getHostByAddrImpl(ipaddress).hostName;
0324: } catch (UnknownHostException e) {
0325: return Inet6Util.createIPAddrStringFromByteArray(ipaddress);
0326: }
0327: SecurityManager security = System.getSecurityManager();
0328: try {
0329: // Only check host names, not addresses
0330: if (security != null && isHostName(canonicalName)) {
0331: security.checkConnect(canonicalName, -1);
0332: }
0333: } catch (SecurityException e) {
0334: return Inet6Util.createIPAddrStringFromByteArray(ipaddress);
0335: }
0336: return canonicalName;
0337: }
0338:
0339: /**
0340: * Answer the local host, if allowed by the security policy. Otherwise,
0341: * answer the loopback address which allows this machine to be contacted.
0342: *
0343: * @return InetAddress the InetAddress representing the local host
0344: * @throws UnknownHostException
0345: * if the address lookup fails
0346: */
0347: public static InetAddress getLocalHost()
0348: throws UnknownHostException {
0349: String host = getHostNameImpl();
0350: SecurityManager security = System.getSecurityManager();
0351: try {
0352: if (security != null) {
0353: security.checkConnect(host, -1);
0354: }
0355: } catch (SecurityException e) {
0356: return InetAddress.LOOPBACK;
0357: }
0358: return lookupHostByName(host);
0359: }
0360:
0361: /**
0362: * Answer a hashcode for this IP address.
0363: *
0364: * @return int the hashcode
0365: */
0366: @Override
0367: public int hashCode() {
0368: return bytesToInt(ipaddress, 0);
0369: }
0370:
0371: /**
0372: * Answer true if the InetAddress is an IP multicast address.
0373: *
0374: * @return boolean true, if the address is in the multicast group
0375: */
0376: public boolean isMulticastAddress() {
0377: return ((ipaddress[0] & 255) >>> 4) == 0xE;
0378: }
0379:
0380: static synchronized InetAddress lookupHostByName(String host)
0381: throws UnknownHostException {
0382: int ttl = -1;
0383:
0384: String ttlValue = AccessController
0385: .doPrivileged(new PriviAction<String>(
0386: "networkaddress.cache.ttl")); //$NON-NLS-1$
0387: try {
0388: if (ttlValue != null) {
0389: ttl = Integer.decode(ttlValue).intValue();
0390: }
0391: } catch (NumberFormatException e) {
0392: // Ignored
0393: }
0394: CacheElement element = null;
0395: if (ttl == 0) {
0396: Cache.clear();
0397: } else {
0398: element = Cache.get(host);
0399: if (element != null
0400: && ttl > 0
0401: && element.timeAdded + (ttl * 1000) < System
0402: .currentTimeMillis()) {
0403: element = null;
0404: }
0405: }
0406: if (element != null) {
0407: return element.inetAddress();
0408: }
0409:
0410: // now try the negative cache
0411: String failedMessage = NegativeCache.getFailedMessage(host);
0412: if (failedMessage != null) {
0413: throw new UnknownHostException(host + " - " + failedMessage); //$NON-NLS-1$
0414: }
0415:
0416: InetAddress anInetAddress;
0417: try {
0418: anInetAddress = getHostByNameImpl(host,
0419: preferIPv6Addresses());
0420: } catch (UnknownHostException e) {
0421: // put the entry in the negative cache
0422: NegativeCache.put(host, e.getMessage());
0423: throw new UnknownHostException(host
0424: + " - " + e.getMessage()); //$NON-NLS-1$
0425: }
0426:
0427: Cache.add(anInetAddress);
0428: return anInetAddress;
0429: }
0430:
0431: /**
0432: * Query the IP stack for aliases for the host. The host is in string name
0433: * form.
0434: *
0435: * @param name
0436: * the host name to lookup
0437: * @throws UnknownHostException
0438: * if an error occurs during lookup
0439: */
0440: static native InetAddress[] getAliasesByNameImpl(String name)
0441: throws UnknownHostException;
0442:
0443: /**
0444: * Query the IP stack for the host address. The host is in address form.
0445: *
0446: * @param addr
0447: * the host address to lookup
0448: * @throws UnknownHostException
0449: * if an error occurs during lookup
0450: */
0451: static native InetAddress getHostByAddrImpl(byte[] addr)
0452: throws UnknownHostException;
0453:
0454: static int inetAddr(String host) throws UnknownHostException {
0455: return (host.equals("255.255.255.255")) ? 0xFFFFFFFF //$NON-NLS-1$
0456: : inetAddrImpl(host);
0457: }
0458:
0459: /**
0460: * Convert a string containing an Ipv4 Internet Protocol dotted address into
0461: * a binary address. Note, the special case of '255.255.255.255' throws an
0462: * exception, so this value should not be used as an argument. See also
0463: * inetAddr(String).
0464: */
0465: static native int inetAddrImpl(String host)
0466: throws UnknownHostException;
0467:
0468: /**
0469: * Convert a binary address into a string containing an Ipv4 Internet
0470: * Protocol dotted address.
0471: */
0472: static native String inetNtoaImpl(int hipAddr);
0473:
0474: /**
0475: * Query the IP stack for the host address. The host is in string name form.
0476: *
0477: * @param name
0478: * the host name to lookup
0479: * @param preferIPv6Addresses
0480: * address preference if underlying platform is V4/V6
0481: * @return InetAddress the host address
0482: *
0483: * @throws UnknownHostException
0484: * if an error occurs during lookup
0485: */
0486: static native InetAddress getHostByNameImpl(String name,
0487: boolean preferIPv6Address) throws UnknownHostException;
0488:
0489: /**
0490: * Query the IP stack for the host machine name.
0491: *
0492: * @return String the host machine name
0493: */
0494: static native String getHostNameImpl();
0495:
0496: static String getHostNameInternal(String host)
0497: throws UnknownHostException {
0498: if (host == null || 0 == host.length()) {
0499: return InetAddress.LOOPBACK.getHostAddress();
0500: }
0501: if (isHostName(host)) {
0502: return lookupHostByName(host).getHostAddress();
0503: }
0504: return host;
0505: }
0506:
0507: /**
0508: * Answers a string containing a concise, human-readable description of the
0509: * address.
0510: *
0511: * @return String the description, as host/address
0512: */
0513: @Override
0514: public String toString() {
0515: return (hostName == null ? "" : hostName) + "/" + getHostAddress(); //$NON-NLS-1$ //$NON-NLS-2$
0516: }
0517:
0518: class CacheElement {
0519: long timeAdded = System.currentTimeMillis();
0520:
0521: CacheElement next;
0522:
0523: public CacheElement() {
0524: super ();
0525: }
0526:
0527: String hostName() {
0528: return hostName;
0529: }
0530:
0531: InetAddress inetAddress() {
0532: return InetAddress.this ;
0533: }
0534: }
0535:
0536: static class Cache {
0537: static int maxSize = 5;
0538:
0539: private static int size = 0;
0540:
0541: private static CacheElement head;
0542:
0543: static void clear() {
0544: size = 0;
0545: head = null;
0546: }
0547:
0548: static void add(InetAddress value) {
0549: CacheElement newElement = value.cacheElement();
0550: if (size < maxSize) {
0551: size++;
0552: } else {
0553: deleteTail();
0554: }
0555: newElement.next = head; // If the head is null, this does no harm.
0556: head = newElement;
0557: }
0558:
0559: static CacheElement get(String name) {
0560: CacheElement previous = null;
0561: CacheElement current = head;
0562: boolean notFound = true;
0563: while ((null != current)
0564: && (notFound = !(name.equals(current.hostName())))) {
0565: previous = current;
0566: current = current.next;
0567: }
0568: if (notFound) {
0569: return null;
0570: }
0571: moveToHead(current, previous);
0572: return current;
0573: }
0574:
0575: private static void deleteTail() {
0576: if (0 == size) {
0577: return;
0578: }
0579: if (1 == size) {
0580: head = null;
0581: }
0582:
0583: CacheElement previous = null;
0584: CacheElement current = head;
0585: while (null != current.next) {
0586: previous = current;
0587: current = current.next;
0588: }
0589: previous.next = null;
0590: }
0591:
0592: private static void moveToHead(CacheElement element,
0593: CacheElement elementPredecessor) {
0594: if (null == elementPredecessor) {
0595: head = element;
0596: } else {
0597: elementPredecessor.next = element.next;
0598: element.next = head;
0599: head = element;
0600: }
0601: }
0602: }
0603:
0604: /**
0605: * Answer true if the string is a host name, false if it is an IP Address.
0606: */
0607: private static boolean isHostName(String value) {
0608: return !(Inet6Util.isValidIPV4Address(value) || Inet6Util
0609: .isValidIP6Address(value));
0610: }
0611:
0612: /**
0613: * Answer true if the address is a loop back address. Valid IPv4 loopback
0614: * addresses are 127.d.d.d Valid IPv6 loopback address is ::1
0615: *
0616: * @return boolean
0617: */
0618: public boolean isLoopbackAddress() {
0619: return false;
0620: }
0621:
0622: /**
0623: * Answers true if the address is a link local address.
0624: *
0625: * Valid IPv6 link local addresses are FE80::0 through to
0626: * FEBF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF
0627: *
0628: * There are no valid IPv4 link local addresses.
0629: *
0630: * @return boolean
0631: */
0632: public boolean isLinkLocalAddress() {
0633: return false;
0634: }
0635:
0636: /**
0637: * Answers true if the address is a site local address.
0638: *
0639: * Valid IPv6 link local addresses are FEC0::0 through to
0640: * FEFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF
0641: *
0642: * There are no valid IPv4 site local addresses.
0643: *
0644: * @return boolean
0645: */
0646: public boolean isSiteLocalAddress() {
0647: return false;
0648: }
0649:
0650: /**
0651: * Answers true if the address is a global multicast address.
0652: *
0653: * Valid IPv6 link global multicast addresses are FFxE:/112 where x is a set
0654: * of flags, and the additional 112 bits make up the global multicast
0655: * address space
0656: *
0657: * Valid IPv4 global multicast addresses are between: 224.0.1.0 to
0658: * 238.255.255.255
0659: *
0660: * @return boolean
0661: */
0662: public boolean isMCGlobal() {
0663: return false;
0664: }
0665:
0666: /**
0667: * Answers true if the address is a node local multicast address.
0668: *
0669: * Valid IPv6 node local multicast addresses are FFx1:/112 where x is a set
0670: * of flags, and the additional 112 bits make up the node local multicast
0671: * address space
0672: *
0673: * There are no valid IPv4 node local multicast addresses.
0674: *
0675: * @return boolean
0676: */
0677: public boolean isMCNodeLocal() {
0678: return false;
0679: }
0680:
0681: /**
0682: * Answers true if the address is a link local multicast address.
0683: *
0684: * Valid IPv6 link local multicast addresses are FFx2:/112 where x is a set
0685: * of flags, and the additional 112 bits make up the node local multicast
0686: * address space
0687: *
0688: * Valid IPv4 link-local addresses are between: 224.0.0.0 to 224.0.0.255
0689: *
0690: * @return boolean
0691: */
0692: public boolean isMCLinkLocal() {
0693: return false;
0694: }
0695:
0696: /**
0697: * Answers true if the address is a site local multicast address.
0698: *
0699: * Valid IPv6 site local multicast addresses are FFx5:/112 where x is a set
0700: * of flags, and the additional 112 bits make up the node local multicast
0701: * address space
0702: *
0703: * Valid IPv4 site-local addresses are between: 239.252.0.0 to
0704: * 239.255.255.255
0705: *
0706: * @return boolean
0707: */
0708: public boolean isMCSiteLocal() {
0709: return false;
0710: }
0711:
0712: /**
0713: * Answers true if the address is a organization local multicast address.
0714: *
0715: * Valid IPv6 organization local multicast addresses are FFx8:/112 where x
0716: * is a set of flags, and the additional 112 bits make up the node local
0717: * multicast address space
0718: *
0719: * Valid IPv4 organization-local addresses are between: 239.192.0.0 to
0720: * 239.251.255.255
0721: *
0722: * @return boolean
0723: */
0724: public boolean isMCOrgLocal() {
0725: return false;
0726: }
0727:
0728: /**
0729: * Method isAnyLocalAddress.
0730: *
0731: * @return boolean
0732: */
0733: public boolean isAnyLocalAddress() {
0734: return false;
0735: }
0736:
0737: /**
0738: * Tries to see if the InetAddress is reachable. This method first tries to
0739: * use ICMP(ICMP ECHO REQUEST). When first step fails, the TCP connection on
0740: * port 7 (Echo) shall be lauched.
0741: *
0742: * @param timeout
0743: * timeout in milliseconds
0744: * @return true if address is reachable
0745: * @throws IOException
0746: * if I/O operation meets error
0747: * @throws IllegalArgumentException
0748: * if timeout is less than zero
0749: */
0750: public boolean isReachable(int timeout) throws IOException {
0751: return isReachable(null, 0, timeout);
0752: }
0753:
0754: /**
0755: * Tries to see if the InetAddress is reachable. This method first tries to
0756: * use ICMP(ICMP ECHO REQUEST). When first step fails, the TCP connection on
0757: * port 7 (Echo) shall be lauched.
0758: *
0759: * @param netif
0760: * the network interface through which to connect
0761: * @param ttl
0762: * max hops to live
0763: * @param timeout
0764: * timeout in milliseconds
0765: * @return true if address is reachable
0766: * @throws IOException
0767: * if I/O operation meets error
0768: * @throws IllegalArgumentException
0769: * if ttl or timeout is less than zero
0770: */
0771: public boolean isReachable(NetworkInterface netif, final int ttl,
0772: final int timeout) throws IOException {
0773: if (0 > ttl || 0 > timeout) {
0774: throw new IllegalArgumentException(Msg.getString("K0051")); //$NON-NLS-1$
0775: }
0776: boolean reachable = false;
0777: if (null == netif) {
0778: // network interface is null, binds to no address
0779: reachable = NETIMPL.isReachableByICMP(this , null, ttl,
0780: timeout);
0781: if (!reachable) {
0782: reachable = isReachableByTCP(this , null, timeout);
0783: }
0784: } else {
0785: // Not Bind to any address
0786: if (null == netif.addresses) {
0787: return false;
0788: }
0789: // binds to all address on this NetworkInterface, tries ICMP ping
0790: // first
0791: reachable = isReachableByICMPUseMultiThread(netif, ttl,
0792: timeout);
0793: if (!reachable) {
0794: // tries TCP echo if ICMP ping fails
0795: reachable = isReachableByTCPUseMultiThread(netif, ttl,
0796: timeout);
0797: }
0798: }
0799: return reachable;
0800: }
0801:
0802: /*
0803: * Uses multi-Thread to try if isReachable, returns true if any of threads
0804: * returns in time
0805: */
0806: private boolean isReachableByMultiThread(NetworkInterface netif,
0807: final int ttl, final int timeout, final boolean isICMP)
0808: throws IOException {
0809: if (null == netif.addresses) {
0810: return false;
0811: }
0812: Enumeration<InetAddress> addresses = netif.getInetAddresses();
0813: reached = false;
0814: addrCount = netif.addresses.length;
0815: boolean needWait = false;
0816: while (addresses.hasMoreElements()) {
0817: final InetAddress addr = addresses.nextElement();
0818:
0819: // loopback interface can only reach to local addresses
0820: if (addr.isLoopbackAddress()) {
0821: Enumeration<NetworkInterface> NetworkInterfaces = NetworkInterface
0822: .getNetworkInterfaces();
0823: while (NetworkInterfaces.hasMoreElements()) {
0824: NetworkInterface networkInterface = NetworkInterfaces
0825: .nextElement();
0826: Enumeration<InetAddress> localAddresses = networkInterface
0827: .getInetAddresses();
0828: while (localAddresses.hasMoreElements()) {
0829: if (InetAddress.this .equals(localAddresses
0830: .nextElement())) {
0831: return true;
0832: }
0833: }
0834: }
0835:
0836: synchronized (waitReachable) {
0837: addrCount--;
0838:
0839: if (addrCount == 0) {
0840: // if count equals zero, all thread
0841: // expired,notifies main thread
0842: waitReachable.notifyAll();
0843: }
0844: }
0845: continue;
0846: }
0847:
0848: needWait = true;
0849: new Thread() {
0850: @Override
0851: public void run() {
0852: boolean threadReached = false;
0853: // if isICMP, tries ICMP ping, else TCP echo
0854: if (isICMP) {
0855: threadReached = NETIMPL.isReachableByICMP(addr,
0856: InetAddress.this , ttl, timeout);
0857: } else {
0858: try {
0859: threadReached = isReachableByTCP(addr,
0860: InetAddress.this , timeout);
0861: } catch (IOException e) {
0862: // do nothing
0863: }
0864: }
0865:
0866: synchronized (waitReachable) {
0867: if (threadReached) {
0868: // if thread reached this address, sets reached to
0869: // true and notifies main thread
0870: reached = true;
0871: waitReachable.notifyAll();
0872: } else {
0873: addrCount--;
0874: if (0 == addrCount) {
0875: // if count equals zero, all thread
0876: // expired,notifies main thread
0877: waitReachable.notifyAll();
0878: }
0879: }
0880: }
0881: }
0882: }.start();
0883: }
0884:
0885: if (needWait) {
0886: synchronized (waitReachable) {
0887: try {
0888: while (!reached && (addrCount != 0)) {
0889: // wait for notification
0890: waitReachable.wait(1000);
0891: }
0892: } catch (InterruptedException e) {
0893: // do nothing
0894: }
0895: return reached;
0896: }
0897: }
0898:
0899: return false;
0900: }
0901:
0902: private boolean isReachableByICMPUseMultiThread(
0903: NetworkInterface netif, int ttl, int timeout)
0904: throws IOException {
0905: return isReachableByMultiThread(netif, ttl, timeout, true);
0906: }
0907:
0908: private boolean isReachableByTCPUseMultiThread(
0909: NetworkInterface netif, int ttl, int timeout)
0910: throws IOException {
0911: return isReachableByMultiThread(netif, ttl, timeout, false);
0912: }
0913:
0914: private boolean isReachableByTCP(InetAddress dest,
0915: InetAddress source, int timeout) throws IOException {
0916: FileDescriptor fd = new FileDescriptor();
0917: // define traffic only for parameter
0918: int traffic = 0;
0919: boolean reached = false;
0920: NETIMPL.createSocket(fd, NetUtil.preferIPv4Stack());
0921: try {
0922: if (null != source) {
0923: NETIMPL.bind(fd, 0, source);
0924: }
0925: NETIMPL.connectStreamWithTimeoutSocket(fd, 7, timeout,
0926: traffic, dest);
0927: reached = true;
0928: } catch (IOException e) {
0929: if (ERRMSG_CONNECTION_REFUSED.equals(e.getMessage())) {
0930: // Connection refused means the IP is reachable
0931: reached = true;
0932: }
0933: }
0934:
0935: NETIMPL.socketClose(fd);
0936:
0937: return reached;
0938: }
0939:
0940: /**
0941: * Answers the InetAddress corresponding to the array of bytes. In the case
0942: * of an IPv4 address there must be exactly 4 bytes and for IPv6 exactly 16
0943: * bytes. If not, an UnknownHostException is thrown.
0944: *
0945: * The IP address is not validated by a name service.
0946: *
0947: * The high order byte is <code>ipAddress[0]</code>.
0948: *
0949: * @param ipAddress
0950: * either a 4 (IPv4) or 16 (IPv6) byte array
0951: * @return the InetAddress
0952: *
0953: * @throws UnknownHostException
0954: */
0955: public static InetAddress getByAddress(byte[] ipAddress)
0956: throws UnknownHostException {
0957: // simply call the method by the same name specifying the default scope
0958: // id of 0
0959: return getByAddress(ipAddress, 0);
0960: }
0961:
0962: /**
0963: * Answers the InetAddress corresponding to the array of bytes. In the case
0964: * of an IPv4 address there must be exactly 4 bytes and for IPv6 exactly 16
0965: * bytes. If not, an UnknownHostException is thrown.
0966: *
0967: * The IP address is not validated by a name service.
0968: *
0969: * The high order byte is <code>ipAddress[0]</code>.
0970: *
0971: * @param ipAddress
0972: * either a 4 (IPv4) or 16 (IPv6) byte array
0973: * @param scope_id
0974: * the scope id for an IPV6 scoped address. If not a scoped
0975: * address just pass in 0
0976: * @return the InetAddress
0977: *
0978: * @throws UnknownHostException
0979: */
0980: static InetAddress getByAddress(byte[] ipAddress, int scope_id)
0981: throws UnknownHostException {
0982: byte[] copy_address;
0983: if (ipAddress != null && ipAddress.length == 4) {
0984: copy_address = new byte[4];
0985: for (int i = 0; i < 4; i++) {
0986: copy_address[i] = ipAddress[i];
0987: }
0988: return new Inet4Address(copy_address);
0989: }
0990:
0991: if (ipAddress != null && ipAddress.length == 16) {
0992: // First check to see if the address is an IPv6-mapped
0993: // IPv4 address. If it is, then we can make it a IPv4
0994: // address, otherwise, we'll create an IPv6 address.
0995: if (isIPv4MappedAddress(ipAddress)) {
0996: copy_address = new byte[4];
0997: for (int i = 0; i < 4; i++) {
0998: copy_address[i] = ipAddress[12 + i];
0999: }
1000: return new Inet4Address(copy_address);
1001: }
1002: copy_address = ipAddress.clone();
1003: return new Inet6Address(copy_address, scope_id);
1004: }
1005:
1006: // K0339=Invalid IP Address is neither 4 or 16 bytes
1007: throw new UnknownHostException(Msg.getString("K0339")); //$NON-NLS-1$
1008: }
1009:
1010: private static boolean isIPv4MappedAddress(byte ipAddress[]) {
1011: // Check if the address matches ::FFFF:d.d.d.d
1012: // The first 10 bytes are 0. The next to are -1 (FF).
1013: // The last 4 bytes are varied.
1014: for (int i = 0; i < 10; i++) {
1015: if (ipAddress[i] != 0) {
1016: return false;
1017: }
1018: }
1019:
1020: if (ipAddress[10] != -1 || ipAddress[11] != -1) {
1021: return false;
1022: }
1023:
1024: return true;
1025: }
1026:
1027: /**
1028: * Answers the InetAddress corresponding to the array of bytes, and the
1029: * given hostname. In the case of an IPv4 address there must be exactly 4
1030: * bytes and for IPv6 exactly 16 bytes. If not, an UnknownHostException is
1031: * thrown.
1032: *
1033: * The host name and IP address are not validated.
1034: *
1035: * The hostname either be a machine alias or a valid IPv6 or IPv4 address
1036: * format.
1037: *
1038: * The high order byte is <code>ipAddress[0]</code>.
1039: *
1040: * @param hostName
1041: * string representation of hostname or ip address
1042: * @param ipAddress
1043: * either a 4 (IPv4) or 16 (IPv6) byte array
1044: * @return the InetAddress
1045: *
1046: * @throws UnknownHostException
1047: */
1048: public static InetAddress getByAddress(String hostName,
1049: byte[] ipAddress) throws UnknownHostException {
1050: // just call the method by the same name passing in a default scope id
1051: // of 0
1052: return getByAddressInternal(hostName, ipAddress, 0);
1053: }
1054:
1055: /**
1056: * Answers the InetAddress corresponding to the array of bytes, and the
1057: * given hostname. In the case of an IPv4 address there must be exactly 4
1058: * bytes and for IPv6 exactly 16 bytes. If not, an UnknownHostException is
1059: * thrown.
1060: *
1061: * The host name and IP address are not validated.
1062: *
1063: * The hostname either be a machine alias or a valid IPv6 or IPv4 address
1064: * format.
1065: *
1066: * The high order byte is <code>ipAddress[0]</code>.
1067: *
1068: * @param hostName
1069: * string representation of hostname or IP address
1070: * @param ipAddress
1071: * either a 4 (IPv4) or 16 (IPv6) byte array
1072: * @param scope_id
1073: * the scope id for a scoped address. If not a scoped address
1074: * just pass in 0
1075: * @return the InetAddress
1076: *
1077: * @throws UnknownHostException
1078: */
1079: static InetAddress getByAddressInternal(String hostName,
1080: byte[] ipAddress, int scope_id) throws UnknownHostException {
1081: byte[] copy_address;
1082: if (ipAddress != null && ipAddress.length == 4) {
1083: copy_address = new byte[4];
1084: for (int i = 0; i < 4; i++) {
1085: copy_address[i] = ipAddress[i];
1086: }
1087: return new Inet4Address(ipAddress, hostName);
1088: }
1089:
1090: if (ipAddress != null && ipAddress.length == 16) {
1091: // First check to see if the address is an IPv6-mapped
1092: // IPv4 address. If it is, then we can make it a IPv4
1093: // address, otherwise, we'll create an IPv6 address.
1094: if (isIPv4MappedAddress(ipAddress)) {
1095: copy_address = new byte[4];
1096: for (int i = 0; i < 4; i++) {
1097: copy_address[i] = ipAddress[12 + i];
1098: }
1099: return new Inet4Address(ipAddress, hostName);
1100: }
1101:
1102: copy_address = new byte[16];
1103: for (int i = 0; i < 16; i++) {
1104: copy_address[i] = ipAddress[i];
1105: }
1106:
1107: return new Inet6Address(ipAddress, hostName, scope_id);
1108: }
1109:
1110: throw new UnknownHostException(Msg.getString("K0332", hostName)); //$NON-NLS-1$
1111: }
1112:
1113: /**
1114: * Takes the integer and chops it into 4 bytes, putting it into the byte
1115: * array starting with the high order byte at the index start. This method
1116: * makes no checks on the validity of the parameters.
1117: */
1118: static void intToBytes(int value, byte bytes[], int start) {
1119: // Shift the int so the current byte is right-most
1120: // Use a byte mask of 255 to single out the last byte.
1121: bytes[start] = (byte) ((value >> 24) & 255);
1122: bytes[start + 1] = (byte) ((value >> 16) & 255);
1123: bytes[start + 2] = (byte) ((value >> 8) & 255);
1124: bytes[start + 3] = (byte) (value & 255);
1125: }
1126:
1127: /**
1128: * Takes the byte array and creates an integer out of four bytes starting at
1129: * start as the high-order byte. This method makes no checks on the validity
1130: * of the parameters.
1131: */
1132: static int bytesToInt(byte bytes[], int start) {
1133: // First mask the byte with 255, as when a negative
1134: // signed byte converts to an integer, it has bits
1135: // on in the first 3 bytes, we are only concerned
1136: // about the right-most 8 bits.
1137: // Then shift the rightmost byte to align with its
1138: // position in the integer.
1139: int value = ((bytes[start + 3] & 255))
1140: | ((bytes[start + 2] & 255) << 8)
1141: | ((bytes[start + 1] & 255) << 16)
1142: | ((bytes[start] & 255) << 24);
1143: return value;
1144: }
1145:
1146: /**
1147: * Creates an InetAddress based on an ipAddressString. No error handling is
1148: * performed here.
1149: */
1150: static InetAddress createHostNameFromIPAddress(
1151: String ipAddressString) throws UnknownHostException {
1152:
1153: InetAddress address = null;
1154:
1155: if (Inet6Util.isValidIPV4Address(ipAddressString)) {
1156: byte[] byteAddress = new byte[4];
1157: String[] parts = ipAddressString.split("\\."); //$NON-NLS-1$
1158: int length = parts.length;
1159: if (length == 1) {
1160: long value = Long.parseLong(parts[0]);
1161: for (int i = 0; i < 4; i++) {
1162: byteAddress[i] = (byte) (value >> ((3 - i) * 8));
1163: }
1164: } else {
1165: for (int i = 0; i < length; i++) {
1166: byteAddress[i] = (byte) Integer.parseInt(parts[i]);
1167: }
1168: }
1169:
1170: // adjust for 2/3 parts address
1171: if (length == 2) {
1172: byteAddress[3] = byteAddress[1];
1173: byteAddress[1] = 0;
1174: }
1175: if (length == 3) {
1176: byteAddress[3] = byteAddress[2];
1177: byteAddress[2] = 0;
1178: }
1179:
1180: address = new Inet4Address(byteAddress);
1181: } else { // otherwise it must be ipv6
1182:
1183: if (ipAddressString.charAt(0) == '[') {
1184: ipAddressString = ipAddressString.substring(1,
1185: ipAddressString.length() - 1);
1186: }
1187:
1188: StringTokenizer tokenizer = new StringTokenizer(
1189: ipAddressString, ":.%", true); //$NON-NLS-1$
1190: ArrayList<String> hexStrings = new ArrayList<String>();
1191: ArrayList<String> decStrings = new ArrayList<String>();
1192: String scopeString = null;
1193: String token = ""; //$NON-NLS-1$
1194: String prevToken = ""; //$NON-NLS-1$
1195: String prevPrevToken = ""; //$NON-NLS-1$
1196: int doubleColonIndex = -1; // If a double colon exists, we need to
1197: // insert 0s.
1198:
1199: // Go through the tokens, including the separators ':' and '.'
1200: // When we hit a : or . the previous token will be added to either
1201: // the hex list or decimal list. In the case where we hit a ::
1202: // we will save the index of the hexStrings so we can add zeros
1203: // in to fill out the string
1204: while (tokenizer.hasMoreTokens()) {
1205: prevPrevToken = prevToken;
1206: prevToken = token;
1207: token = tokenizer.nextToken();
1208:
1209: if (token.equals(":")) { //$NON-NLS-1$
1210: if (prevToken.equals(":")) { //$NON-NLS-1$
1211: doubleColonIndex = hexStrings.size();
1212: } else if (!prevToken.equals("")) { //$NON-NLS-1$
1213: hexStrings.add(prevToken);
1214: }
1215: } else if (token.equals(".")) { //$NON-NLS-1$
1216: decStrings.add(prevToken);
1217: } else if (token.equals("%")) { //$NON-NLS-1$
1218: // add the last word before the % properly
1219: if (!prevToken.equals(":") && !prevToken.equals(".")) { //$NON-NLS-1$ //$NON-NLS-2$
1220: if (prevPrevToken.equals(":")) { //$NON-NLS-1$
1221: hexStrings.add(prevToken);
1222: } else if (prevPrevToken.equals(".")) { //$NON-NLS-1$
1223: decStrings.add(prevToken);
1224: }
1225: }
1226:
1227: // the rest should be the scope string
1228: scopeString = tokenizer.nextToken();
1229: while (tokenizer.hasMoreTokens()) {
1230: scopeString = scopeString
1231: + tokenizer.nextToken();
1232: }
1233: }
1234: }
1235:
1236: if (prevToken.equals(":")) { //$NON-NLS-1$
1237: if (token.equals(":")) { //$NON-NLS-1$
1238: doubleColonIndex = hexStrings.size();
1239: } else {
1240: hexStrings.add(token);
1241: }
1242: } else if (prevToken.equals(".")) { //$NON-NLS-1$
1243: decStrings.add(token);
1244: }
1245:
1246: // figure out how many hexStrings we should have
1247: // also check if it is a IPv4 address
1248: int hexStringsLength = 8;
1249:
1250: // If we have an IPv4 address tagged on at the end, subtract
1251: // 4 bytes, or 2 hex words from the total
1252: if (decStrings.size() > 0) {
1253: hexStringsLength -= 2;
1254: }
1255:
1256: // if we hit a double Colon add the appropriate hex strings
1257: if (doubleColonIndex != -1) {
1258: int numberToInsert = hexStringsLength
1259: - hexStrings.size();
1260: for (int i = 0; i < numberToInsert; i++) {
1261: hexStrings.add(doubleColonIndex, "0"); //$NON-NLS-1$
1262: }
1263: }
1264:
1265: byte ipByteArray[] = new byte[16];
1266:
1267: // Finally convert these strings to bytes...
1268: for (int i = 0; i < hexStrings.size(); i++) {
1269: Inet6Util.convertToBytes(hexStrings.get(i),
1270: ipByteArray, i * 2);
1271: }
1272:
1273: // Now if there are any decimal values, we know where they go...
1274: for (int i = 0; i < decStrings.size(); i++) {
1275: ipByteArray[i + 12] = (byte) (Integer
1276: .parseInt(decStrings.get(i)) & 255);
1277: }
1278:
1279: // now check to see if this guy is actually and IPv4 address
1280: // an ipV4 address is ::FFFF:d.d.d.d
1281: boolean ipV4 = true;
1282: for (int i = 0; i < 10; i++) {
1283: if (ipByteArray[i] != 0) {
1284: ipV4 = false;
1285: break;
1286: }
1287: }
1288:
1289: if (ipByteArray[10] != -1 || ipByteArray[11] != -1) {
1290: ipV4 = false;
1291: }
1292:
1293: if (ipV4) {
1294: byte ipv4ByteArray[] = new byte[4];
1295: for (int i = 0; i < 4; i++) {
1296: ipv4ByteArray[i] = ipByteArray[i + 12];
1297: }
1298: address = InetAddress.getByAddress(ipv4ByteArray);
1299: } else {
1300: int scopeId = 0;
1301: if (scopeString != null) {
1302: try {
1303: scopeId = Integer.parseInt(scopeString);
1304: } catch (Exception e) {
1305: // this should not occur as we should not get into this
1306: // function unless the address is in a valid format
1307: }
1308: }
1309: address = InetAddress
1310: .getByAddress(ipByteArray, scopeId);
1311: }
1312: }
1313:
1314: return address;
1315: }
1316:
1317: static boolean preferIPv6Addresses() {
1318: String result = AccessController
1319: .doPrivileged(new PriviAction<String>(
1320: "java.net.preferIPv6Addresses")); //$NON-NLS-1$
1321: return "true".equals(result); //$NON-NLS-1$
1322: }
1323:
1324: private static final ObjectStreamField[] serialPersistentFields = {
1325: new ObjectStreamField("address", Integer.TYPE), //$NON-NLS-1$
1326: new ObjectStreamField("family", Integer.TYPE), //$NON-NLS-1$
1327: new ObjectStreamField("hostName", String.class) }; //$NON-NLS-1$
1328:
1329: private void writeObject(ObjectOutputStream stream)
1330: throws IOException {
1331: ObjectOutputStream.PutField fields = stream.putFields();
1332: if (ipaddress == null) {
1333: fields.put("address", 0); //$NON-NLS-1$
1334: } else {
1335: fields.put("address", bytesToInt(ipaddress, 0)); //$NON-NLS-1$
1336: }
1337: fields.put("family", family); //$NON-NLS-1$
1338: fields.put("hostName", hostName); //$NON-NLS-1$
1339:
1340: stream.writeFields();
1341: }
1342:
1343: private void readObject(ObjectInputStream stream)
1344: throws IOException, ClassNotFoundException {
1345: ObjectInputStream.GetField fields = stream.readFields();
1346: int addr = fields.get("address", 0); //$NON-NLS-1$
1347: ipaddress = new byte[4];
1348: intToBytes(addr, ipaddress, 0);
1349: hostName = (String) fields.get("hostName", null); //$NON-NLS-1$
1350: family = fields.get("family", 2); //$NON-NLS-1$
1351: }
1352:
1353: private Object readResolve() throws ObjectStreamException {
1354: return new Inet4Address(ipaddress, hostName);
1355: }
1356: }
|