GNU Classpath (0.19) | ||
Frames | No Frames |
1: /* InetAddress.java -- Class to model an Internet address 2: Copyright (C) 1998, 1999, 2002, 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.net; 40: 41: import java.io.IOException; 42: import java.io.ObjectInputStream; 43: import java.io.ObjectOutputStream; 44: import java.io.ObjectStreamException; 45: import java.io.Serializable; 46: import java.util.HashMap; 47: import java.util.StringTokenizer; 48: 49: /** 50: * This class models an Internet address. It does not have a public 51: * constructor. Instead, new instances of this objects are created 52: * using the static methods getLocalHost(), getByName(), and 53: * getAllByName(). 54: * 55: * <p>This class fulfills the function of the C style functions gethostname(), 56: * gethostbyname(), and gethostbyaddr(). It resolves Internet DNS names 57: * into their corresponding numeric addresses and vice versa.</p> 58: * 59: * @author Aaron M. Renn (arenn@urbanophile.com) 60: * @author Per Bothner 61: * 62: * @specnote This class is not final since JK 1.4 63: */ 64: public class InetAddress implements Serializable 65: { 66: private static final long serialVersionUID = 3286316764910316507L; 67: 68: /** 69: * The default DNS hash table size, 70: * Use a prime number happy with hash table. 71: */ 72: private static final int DEFAULT_CACHE_SIZE = 89; 73: 74: /** 75: * The default caching period in minutes. 76: */ 77: private static final int DEFAULT_CACHE_PERIOD = 4 * 60; 78: 79: /** 80: * Percentage of cache entries to purge when the table gets full. 81: */ 82: private static final int DEFAULT_CACHE_PURGE_PCT = 30; 83: 84: /** 85: * The special IP address INADDR_ANY. 86: */ 87: private static InetAddress inaddr_any; 88: 89: /** 90: * Dummy InetAddress, used to bind socket to any (all) network interfaces. 91: */ 92: static InetAddress ANY_IF; 93: 94: /** 95: * Stores static localhost address object. 96: */ 97: static InetAddress LOCALHOST; 98: 99: /** 100: * The size of the cache. 101: */ 102: private static int cache_size = 0; 103: 104: /** 105: * The length of time we will continue to read the address from cache 106: * before forcing another lookup. 107: */ 108: private static int cache_period = 0; 109: 110: /** 111: * What percentage of the cache we will purge if it gets full. 112: */ 113: private static int cache_purge_pct = 0; 114: 115: /** 116: * HashMap to use as DNS lookup cache. 117: * Use HashMap because all accesses to cache are already synchronized. 118: */ 119: private static HashMap cache; 120: 121: static 122: { 123: // Look for properties that override default caching behavior 124: cache_size = 125: Integer.getInteger("gnu.java.net.dns_cache_size", DEFAULT_CACHE_SIZE) 126: .intValue(); 127: cache_period = 128: Integer.getInteger("gnu.java.net.dns_cache_period", 129: DEFAULT_CACHE_PERIOD * 60 * 1000).intValue(); 130: 131: cache_purge_pct = 132: Integer.getInteger("gnu.java.net.dns_cache_purge_pct", 133: DEFAULT_CACHE_PURGE_PCT).intValue(); 134: 135: // Fallback to defaults if necessary 136: if ((cache_purge_pct < 1) || (cache_purge_pct > 100)) 137: cache_purge_pct = DEFAULT_CACHE_PURGE_PCT; 138: 139: // Create the cache 140: if (cache_size != 0) 141: cache = new HashMap(cache_size); 142: 143: // precompute the ANY_IF address 144: try 145: { 146: ANY_IF = getInaddrAny(); 147: 148: byte[] ip_localhost = { 127, 0, 0, 1 }; 149: LOCALHOST = new Inet4Address(ip_localhost, "localhost"); 150: } 151: catch (UnknownHostException uhe) 152: { 153: // Hmmm, make one up and hope that it works. 154: byte[] zeros = { 0, 0, 0, 0 }; 155: ANY_IF = new Inet4Address(zeros, "0.0.0.0"); 156: } 157: } 158: 159: /** 160: * The Serialized Form specifies that an int 'address' is saved/restored. 161: * This class uses a byte array internally so we'll just do the conversion 162: * at serialization time and leave the rest of the algorithm as is. 163: */ 164: private int address; 165: 166: /** 167: * An array of octets representing an IP address. 168: */ 169: transient byte[] addr; 170: 171: /** 172: * The name of the host for this address. 173: */ 174: String hostName; 175: 176: /** 177: * The time this address was looked up. 178: */ 179: transient long lookup_time; 180: 181: /** 182: * The field 'family' seems to be the AF_ value. 183: * FIXME: Much of the code in the other java.net classes does not make 184: * use of this family field. A better implementation would be to make 185: * use of getaddrinfo() and have other methods just check the family 186: * field rather than examining the length of the address each time. 187: */ 188: int family; 189: 190: /** 191: * Initializes this object's addr instance variable from the passed in 192: * byte array. Note that this constructor is protected and is called 193: * only by static methods in this class. 194: * 195: * @param ipaddr The IP number of this address as an array of bytes 196: * @param hostname The hostname of this IP address. 197: */ 198: InetAddress(byte[] ipaddr, String hostname) 199: { 200: addr = (null == ipaddr) ? null : (byte[]) ipaddr.clone(); 201: hostName = hostname; 202: 203: lookup_time = System.currentTimeMillis(); 204: 205: family = 2; /* AF_INET */ 206: } 207: 208: /** 209: * Returns true if this address is a multicast address, false otherwise. 210: * An address is multicast if the high four bits are "1110". These are 211: * also known as "Class D" addresses. 212: * 213: * @return true if mulitcast, false if not 214: * 215: * @since 1.1 216: */ 217: public boolean isMulticastAddress() 218: { 219: // Mask against high order bits of 1110 220: if (addr.length == 4) 221: return (addr[0] & 0xf0) == 0xe0; 222: 223: return false; 224: } 225: 226: /** 227: * Utility routine to check if the InetAddress in a wildcard address 228: * 229: * @since 1.4 230: */ 231: public boolean isAnyLocalAddress() 232: { 233: // This is the IPv4 implementation. 234: // Any class derived from InetAddress should override this. 235: return equals(ANY_IF); 236: } 237: 238: /** 239: * Utility routine to check if the InetAddress is a loopback address 240: * 241: * @since 1.4 242: */ 243: public boolean isLoopbackAddress() 244: { 245: // This is the IPv4 implementation. 246: // Any class derived from InetAddress should override this. 247: return (addr[0] & 0xff) == 0x7f; 248: } 249: 250: /** 251: * Utility routine to check if InetAddress is a link local address 252: * 253: * @since 1.4 254: */ 255: public boolean isLinkLocalAddress() 256: { 257: // This is the IPv4 implementation. 258: // Any class derived from InetAddress should override this. 259: // XXX: This seems to not exist with IPv4 addresses 260: return false; 261: } 262: 263: /** 264: * Utility routine to check if InetAddress is a site local address 265: * 266: * @since 1.4 267: */ 268: public boolean isSiteLocalAddress() 269: { 270: // This is the IPv4 implementation. 271: // Any class derived from InetAddress should override this. 272: 273: // 10.0.0.0/8 274: if ((addr[0] & 0xff) == 0x0a) 275: return true; 276: 277: // 172.16.0.0/12 278: if ((addr[0] & 0xff) == 0xac && (addr[1] & 0xf0) == 0x10) 279: return true; 280: 281: // 192.168.0.0/16 282: if ((addr[0] & 0xff) == 0xc0 && (addr[1] & 0xff) == 0xa8) 283: return true; 284: 285: // XXX: Do we need to check more addresses here ? 286: return false; 287: } 288: 289: /** 290: * Utility routine to check if InetAddress is a global multicast address 291: * 292: * @since 1.4 293: */ 294: public boolean isMCGlobal() 295: { 296: // This is the IPv4 implementation. 297: // Any class derived from InetAddress should override this. 298: // XXX: This seems to not exist with IPv4 addresses 299: return false; 300: } 301: 302: /** 303: * Utility routine to check if InetAddress is a node local multicast address. 304: * 305: * @since 1.4 306: */ 307: public boolean isMCNodeLocal() 308: { 309: // This is the IPv4 implementation. 310: // Any class derived from InetAddress should override this. 311: // XXX: This seems to not exist with IPv4 addresses 312: return false; 313: } 314: 315: /** 316: * Utility routine to check if InetAddress is a link local multicast address. 317: * 318: * @since 1.4 319: */ 320: public boolean isMCLinkLocal() 321: { 322: // This is the IPv4 implementation. 323: // Any class derived from InetAddress should override this. 324: if (! isMulticastAddress()) 325: return false; 326: 327: return ((addr[0] & 0xff) == 0xe0 328: && (addr[1] & 0xff) == 0x00 329: && (addr[2] & 0xff) == 0x00); 330: } 331: 332: /** 333: * Utility routine to check if InetAddress is a site local multicast address. 334: * 335: * @since 1.4 336: */ 337: public boolean isMCSiteLocal() 338: { 339: // This is the IPv4 implementation. 340: // Any class derived from InetAddress should override this. 341: // XXX: This seems to not exist with IPv4 addresses 342: return false; 343: } 344: 345: /** 346: * Utility routine to check if InetAddress is a organization local 347: * multicast address. 348: * 349: * @since 1.4 350: */ 351: public boolean isMCOrgLocal() 352: { 353: // This is the IPv4 implementation. 354: // Any class derived from InetAddress should override this. 355: // XXX: This seems to not exist with IPv4 addresses 356: return false; 357: } 358: 359: /** 360: * Returns the hostname for this address. This will return the IP address 361: * as a String if there is no hostname available for this address 362: * 363: * @return The hostname for this address 364: */ 365: public String getHostName() 366: { 367: if (hostName != null) 368: return hostName; 369: 370: try 371: { 372: hostName = VMInetAddress.getHostByAddr(addr); 373: return hostName; 374: } 375: catch (UnknownHostException e) 376: { 377: return getHostAddress(); 378: } 379: } 380: 381: /** 382: * Returns the canonical hostname represented by this InetAddress 383: * 384: * @since 1.4 385: */ 386: public String getCanonicalHostName() 387: { 388: SecurityManager sm = System.getSecurityManager(); 389: if (sm != null) 390: { 391: try 392: { 393: sm.checkConnect(hostName, -1); 394: } 395: catch (SecurityException e) 396: { 397: return getHostAddress(); 398: } 399: } 400: 401: // Try to find the FDQN now 402: InetAddress address; 403: byte[] ipaddr = getAddress(); 404: 405: if (ipaddr.length == 16) 406: address = new Inet6Address(getAddress(), null); 407: else 408: address = new Inet4Address(getAddress(), null); 409: 410: return address.getHostName(); 411: } 412: 413: /** 414: * Returns the IP address of this object as a byte array. 415: * 416: * @return IP address 417: */ 418: public byte[] getAddress() 419: { 420: // An experiment shows that JDK1.2 returns a different byte array each 421: // time. This makes sense, in terms of security. 422: return (byte[]) addr.clone(); 423: } 424: 425: /** 426: * Returns the IP address of this object as a String. The address is in 427: * the dotted octet notation, for example, "127.0.0.1". 428: * 429: * @return The IP address of this object in String form 430: * 431: * @since 1.0.2 432: */ 433: public String getHostAddress() 434: { 435: StringBuffer sb = new StringBuffer(40); 436: 437: int len = addr.length; 438: int i = 0; 439: 440: for ( ; ; ) 441: { 442: sb.append(addr[i] & 0xff); 443: i++; 444: 445: if (i == len) 446: break; 447: 448: sb.append('.'); 449: } 450: 451: return sb.toString(); 452: } 453: 454: /** 455: * Returns a hash value for this address. Useful for creating hash 456: * tables. Overrides Object.hashCode() 457: * 458: * @return A hash value for this address. 459: */ 460: public int hashCode() 461: { 462: // There hashing algorithm is not specified, but a simple experiment 463: // shows that it is equal to the address, as a 32-bit big-endian integer. 464: int hash = 0; 465: int len = addr.length; 466: int i = len > 4 ? len - 4 : 0; 467: 468: for (; i < len; i++) 469: hash = (hash << 8) | (addr[i] & 0xff); 470: 471: return hash; 472: } 473: 474: /** 475: * Tests this address for equality against another InetAddress. The two 476: * addresses are considered equal if they contain the exact same octets. 477: * This implementation overrides Object.equals() 478: * 479: * @param obj The address to test for equality 480: * 481: * @return true if the passed in object's address is equal to this one's, 482: * false otherwise 483: */ 484: public boolean equals(Object obj) 485: { 486: if (! (obj instanceof InetAddress)) 487: return false; 488: 489: // "The Java Class Libraries" 2nd edition says "If a machine has 490: // multiple names instances of InetAddress for different name of 491: // that same machine are not equal. This is because they have 492: // different host names." This violates the description in the 493: // JDK 1.2 API documentation. A little experimentation 494: // shows that the latter is correct. 495: byte[] addr2 = ((InetAddress) obj).addr; 496: 497: if (addr.length != addr2.length) 498: return false; 499: 500: for (int i = 0; i < addr.length; i++) 501: if (addr[i] != addr2[i]) 502: return false; 503: 504: return true; 505: } 506: 507: /** 508: * Converts this address to a String. This string contains the IP in 509: * dotted decimal form. For example: "127.0.0.1" This method is equivalent 510: * to getHostAddress() and overrides Object.toString() 511: * 512: * @return This address in String form 513: */ 514: public String toString() 515: { 516: String addr = getHostAddress(); 517: String host = (hostName != null) ? hostName : ""; 518: return host + "/" + addr; 519: } 520: 521: /** 522: * Returns an InetAddress object given the raw IP address. 523: * 524: * The argument is in network byte order: the highest order byte of the 525: * address is in getAddress()[0]. 526: * 527: * @param addr The IP address to create the InetAddress object from 528: * 529: * @exception UnknownHostException If IP address has illegal length 530: * 531: * @since 1.4 532: */ 533: public static InetAddress getByAddress(byte[] addr) 534: throws UnknownHostException 535: { 536: return getByAddress(null, addr); 537: } 538: 539: /** 540: * Creates an InetAddress based on the provided host name and IP address. 541: * No name service is checked for the validity of the address. 542: * 543: * @param host The hostname of the InetAddress object to create 544: * @param addr The IP address to create the InetAddress object from 545: * 546: * @exception UnknownHostException If IP address is of illegal length 547: * 548: * @since 1.4 549: */ 550: public static InetAddress getByAddress(String host, byte[] addr) 551: throws UnknownHostException 552: { 553: if (addr.length == 4) 554: return new Inet4Address(addr, host); 555: 556: if (addr.length == 16) 557: return new Inet6Address(addr, host); 558: 559: throw new UnknownHostException("IP address has illegal length"); 560: } 561: 562: /** 563: * If hostname is a valid numeric IP address, return the numeric address. 564: * Otherwise, return null. 565: * 566: * @param hostname the name of the host 567: */ 568: private static byte[] aton(String hostname) 569: { 570: StringTokenizer st = new StringTokenizer(hostname, "."); 571: 572: if (st.countTokens() == 4) 573: { 574: int index; 575: byte[] address = new byte[4]; 576: 577: for (index = 0; index < 4; index++) 578: { 579: try 580: { 581: short n = Short.parseShort(st.nextToken()); 582: 583: if ((n < 0) || (n > 255)) 584: break; 585: 586: address[index] = (byte) n; 587: } 588: catch (NumberFormatException e) 589: { 590: break; 591: } 592: } 593: 594: if (index == 4) 595: return address; 596: } 597: 598: return null; 599: } 600: 601: /** 602: * Returns an InetAddress object representing the IP address of the given 603: * hostname. This name can be either a hostname such as "www.urbanophile.com" 604: * or an IP address in dotted decimal format such as "127.0.0.1". If the 605: * hostname is null or "", the hostname of the local machine is supplied by 606: * default. This method is equivalent to returning the first element in 607: * the InetAddress array returned from GetAllByName. 608: * 609: * @param hostname The name of the desired host, or null for the local 610: * loopback address. 611: * 612: * @return The address of the host as an InetAddress object. 613: * 614: * @exception UnknownHostException If no IP address for the host could 615: * be found 616: * @exception SecurityException If a security manager exists and its 617: * checkConnect method doesn't allow the operation 618: */ 619: public static InetAddress getByName(String hostname) 620: throws UnknownHostException 621: { 622: InetAddress[] addresses = getAllByName(hostname); 623: return addresses[0]; 624: } 625: 626: /** 627: * Returns an array of InetAddress objects representing all the host/ip 628: * addresses of a given host, given the host's name. This name can be 629: * either a hostname such as "www.urbanophile.com" or an IP address in 630: * dotted decimal format such as "127.0.0.1". If the value is null, the 631: * hostname of the local machine is supplied by default. 632: * 633: * @param hostname The name of the desired host, or null for the 634: * local loopback address. 635: * 636: * @return All addresses of the host as an array of InetAddress objects. 637: * 638: * @exception UnknownHostException If no IP address for the host could 639: * be found 640: * @exception SecurityException If a security manager exists and its 641: * checkConnect method doesn't allow the operation 642: */ 643: public static InetAddress[] getAllByName(String hostname) 644: throws UnknownHostException 645: { 646: SecurityManager s = System.getSecurityManager(); 647: if (s != null) 648: s.checkConnect(hostname, -1); 649: 650: InetAddress[] addresses; 651: 652: // Default to current host if necessary 653: if (hostname == null) 654: { 655: addresses = new InetAddress[1]; 656: addresses[0] = LOCALHOST; 657: return addresses; 658: } 659: 660: // Check the cache for this host before doing a lookup 661: addresses = checkCacheFor(hostname); 662: 663: if (addresses != null) 664: return addresses; 665: 666: // Not in cache, try the lookup 667: byte[][] iplist = VMInetAddress.getHostByName(hostname); 668: 669: if (iplist.length == 0) 670: throw new UnknownHostException(hostname); 671: 672: addresses = new InetAddress[iplist.length]; 673: 674: for (int i = 0; i < iplist.length; i++) 675: { 676: if (iplist[i].length != 4) 677: throw new UnknownHostException(hostname); 678: 679: addresses[i] = new Inet4Address(iplist[i], hostname); 680: } 681: 682: addToCache(hostname, addresses); 683: return addresses; 684: } 685: 686: /** 687: * This method checks the DNS cache to see if we have looked this hostname 688: * up before. If so, we return the cached addresses unless it has been in the 689: * cache too long. 690: * 691: * @param hostname The hostname to check for 692: * 693: * @return The InetAddress for this hostname or null if not available 694: */ 695: private static synchronized InetAddress[] checkCacheFor(String hostname) 696: { 697: InetAddress[] addresses = null; 698: 699: if (cache_size == 0) 700: return null; 701: 702: Object obj = cache.get(hostname); 703: if (obj == null) 704: return null; 705: 706: if (obj instanceof InetAddress[]) 707: addresses = (InetAddress[]) obj; 708: 709: if (addresses == null) 710: return null; 711: 712: if (cache_period != -1) 713: if ((System.currentTimeMillis() - addresses[0].lookup_time) > cache_period) 714: { 715: cache.remove(hostname); 716: return null; 717: } 718: 719: return addresses; 720: } 721: 722: /** 723: * This method adds an InetAddress object to our DNS cache. Note that 724: * if the cache is full, then we run a purge to get rid of old entries. 725: * This will cause a performance hit, thus applications using lots of 726: * lookups should set the cache size to be very large. 727: * 728: * @param hostname The hostname to cache this address under 729: * @param obj The InetAddress or InetAddress array to store 730: */ 731: private static synchronized void addToCache(String hostname, Object obj) 732: { 733: if (cache_size == 0) 734: return; 735: 736: // Check to see if hash table is full 737: if (cache_size != -1) 738: if (cache.size() == cache_size) 739: { 740: // FIXME Add code to purge later. 741: } 742: 743: cache.put(hostname, obj); 744: } 745: 746: /** 747: * Returns the special address INADDR_ANY used for binding to a local 748: * port on all IP addresses hosted by a the local host. 749: * 750: * @return An InetAddress object representing INDADDR_ANY 751: * 752: * @exception UnknownHostException If an error occurs 753: */ 754: static InetAddress getInaddrAny() throws UnknownHostException 755: { 756: if (inaddr_any == null) 757: { 758: byte[] tmp = VMInetAddress.lookupInaddrAny(); 759: inaddr_any = new Inet4Address(tmp, null); 760: } 761: 762: return inaddr_any; 763: } 764: 765: /** 766: * Returns an InetAddress object representing the address of the current 767: * host. 768: * 769: * @return The local host's address 770: * 771: * @exception UnknownHostException If no IP address for the host could 772: * be found 773: */ 774: public static InetAddress getLocalHost() throws UnknownHostException 775: { 776: String hostname = VMInetAddress.getLocalHostname(); 777: return getByName(hostname); 778: } 779: 780: /* 781: * Needed for serialization 782: */ 783: private void readResolve() throws ObjectStreamException 784: { 785: // FIXME: implement this 786: } 787: 788: private void readObject(ObjectInputStream ois) 789: throws IOException, ClassNotFoundException 790: { 791: ois.defaultReadObject(); 792: addr = new byte[4]; 793: addr[3] = (byte) address; 794: 795: for (int i = 2; i >= 0; --i) 796: addr[i] = (byte) (address >>= 8); 797: 798: family = 2; /* AF_INET */ 799: } 800: 801: private void writeObject(ObjectOutputStream oos) throws IOException 802: { 803: // Build a 32 bit address from the last 4 bytes of a 4 byte IPv4 address 804: // or a 16 byte IPv6 address. 805: int len = addr.length; 806: int i = len - 4; 807: 808: for (; i < len; i++) 809: address = address << 8 | (addr[i] & 0xff); 810: 811: oos.defaultWriteObject(); 812: } 813: }
GNU Classpath (0.19) |