1 |
/* InetAddress.java -- Class to model an Internet address |
/* InetAddress.java -- Class to model an Internet address |
2 |
Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc. |
Copyright (C) 1998, 1999, 2002, 2004 Free Software Foundation, Inc. |
3 |
|
|
4 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
5 |
|
|
35 |
obligated to do so. If you do not wish to do so, delete this |
obligated to do so. If you do not wish to do so, delete this |
36 |
exception statement from your version. */ |
exception statement from your version. */ |
37 |
|
|
38 |
|
|
39 |
package java.net; |
package java.net; |
40 |
|
|
41 |
import gnu.classpath.Configuration; |
import gnu.classpath.Configuration; |
42 |
|
|
43 |
import java.io.IOException; |
import java.io.IOException; |
44 |
import java.io.ObjectInputStream; |
import java.io.ObjectInputStream; |
45 |
import java.io.ObjectOutputStream; |
import java.io.ObjectOutputStream; |
48 |
import java.util.HashMap; |
import java.util.HashMap; |
49 |
import java.util.StringTokenizer; |
import java.util.StringTokenizer; |
50 |
|
|
|
|
|
51 |
/** |
/** |
52 |
* This class models an Internet address. It does not have a public |
* This class models an Internet address. It does not have a public |
53 |
* constructor. Instead, new instances of this objects are created |
* constructor. Instead, new instances of this objects are created |
54 |
* using the static methods getLocalHost(), getByName(), and |
* using the static methods getLocalHost(), getByName(), and |
55 |
* getAllByName(). |
* getAllByName(). |
56 |
* <p> |
* |
57 |
* This class fulfills the function of the C style functions gethostname(), |
* <p>This class fulfills the function of the C style functions gethostname(), |
58 |
* gethostbyname(), and gethostbyaddr(). It resolves Internet DNS names |
* gethostbyname(), and gethostbyaddr(). It resolves Internet DNS names |
59 |
* into their corresponding numeric addresses and vice versa. |
* into their corresponding numeric addresses and vice versa.</p> |
60 |
* |
* |
61 |
* @author Aaron M. Renn <arenn@urbanophile.com> |
* @author Aaron M. Renn (arenn@urbanophile.com) |
62 |
* @author Per Bothner |
* @author Per Bothner |
63 |
* |
* |
64 |
* @specnote This class is not final since JK 1.4 |
* @specnote This class is not final since JK 1.4 |
76 |
/** |
/** |
77 |
* The default caching period in minutes. |
* The default caching period in minutes. |
78 |
*/ |
*/ |
79 |
private static final int DEFAULT_CACHE_PERIOD = (4 * 60); |
private static final int DEFAULT_CACHE_PERIOD = 4 * 60; |
80 |
|
|
81 |
/** |
/** |
82 |
* Percentage of cache entries to purge when the table gets full. |
* Percentage of cache entries to purge when the table gets full. |
94 |
static InetAddress ANY_IF; |
static InetAddress ANY_IF; |
95 |
|
|
96 |
/** |
/** |
97 |
|
* Stores static localhost address object. |
98 |
|
*/ |
99 |
|
static InetAddress LOCALHOST; |
100 |
|
|
101 |
|
/** |
102 |
* The size of the cache. |
* The size of the cache. |
103 |
*/ |
*/ |
104 |
private static int cache_size = 0; |
private static int cache_size = 0; |
121 |
private static HashMap cache; |
private static HashMap cache; |
122 |
|
|
123 |
static |
static |
124 |
{ |
{ |
125 |
// load the shared library needed for name resolution |
// load the shared library needed for name resolution |
126 |
if (Configuration.INIT_LOAD_LIBRARY) |
if (Configuration.INIT_LOAD_LIBRARY) |
127 |
System.loadLibrary("javanet"); |
System.loadLibrary("javanet"); |
128 |
|
|
129 |
// Look for properties that override default caching behavior |
// Look for properties that override default caching behavior |
130 |
cache_size = |
cache_size = |
131 |
Integer.getInteger("gnu.java.net.dns_cache_size", DEFAULT_CACHE_SIZE) |
Integer.getInteger("gnu.java.net.dns_cache_size", DEFAULT_CACHE_SIZE) |
132 |
.intValue(); |
.intValue(); |
133 |
cache_period = |
cache_period = |
134 |
Integer.getInteger("gnu.java.net.dns_cache_period", |
Integer.getInteger("gnu.java.net.dns_cache_period", |
135 |
DEFAULT_CACHE_PERIOD * 60 * 1000).intValue(); |
DEFAULT_CACHE_PERIOD * 60 * 1000).intValue(); |
136 |
|
|
137 |
cache_purge_pct = |
cache_purge_pct = |
138 |
Integer.getInteger("gnu.java.net.dns_cache_purge_pct", |
Integer.getInteger("gnu.java.net.dns_cache_purge_pct", |
139 |
DEFAULT_CACHE_PURGE_PCT).intValue(); |
DEFAULT_CACHE_PURGE_PCT).intValue(); |
140 |
|
|
141 |
// Fallback to defaults if necessary |
// Fallback to defaults if necessary |
142 |
if ((cache_purge_pct < 1) || (cache_purge_pct > 100)) |
if ((cache_purge_pct < 1) || (cache_purge_pct > 100)) |
143 |
cache_purge_pct = DEFAULT_CACHE_PURGE_PCT; |
cache_purge_pct = DEFAULT_CACHE_PURGE_PCT; |
144 |
|
|
145 |
// Create the cache |
// Create the cache |
146 |
if (cache_size != 0) |
if (cache_size != 0) |
147 |
cache = new HashMap(cache_size); |
cache = new HashMap(cache_size); |
148 |
|
|
149 |
// precompute the ANY_IF address |
// precompute the ANY_IF address |
150 |
try |
try |
151 |
{ |
{ |
152 |
ANY_IF = getInaddrAny(); |
ANY_IF = getInaddrAny(); |
153 |
} |
|
154 |
catch (UnknownHostException uhe) |
byte[] ip_localhost = { 127, 0, 0, 1 }; |
155 |
{ |
LOCALHOST = new Inet4Address(ip_localhost, "localhost"); |
156 |
// Hmmm, make one up and hope that it works. |
} |
157 |
byte[] zeros = { 0, 0, 0, 0 }; |
catch (UnknownHostException uhe) |
158 |
ANY_IF = new Inet4Address(zeros); |
{ |
159 |
} |
// Hmmm, make one up and hope that it works. |
160 |
} |
byte[] zeros = { 0, 0, 0, 0 }; |
161 |
|
ANY_IF = new Inet4Address(zeros, "0.0.0.0"); |
162 |
|
} |
163 |
|
} |
164 |
|
|
165 |
/** |
/** |
166 |
* The Serialized Form specifies that an int 'address' is saved/restored. |
* The Serialized Form specifies that an int 'address' is saved/restored. |
180 |
String hostName; |
String hostName; |
181 |
|
|
182 |
/** |
/** |
|
* Backup hostname alias for this address. |
|
|
*/ |
|
|
transient String hostname_alias; |
|
|
|
|
|
/** |
|
183 |
* The time this address was looked up. |
* The time this address was looked up. |
184 |
*/ |
*/ |
185 |
transient long lookup_time; |
transient long lookup_time; |
200 |
* |
* |
201 |
* @param ipaddr The IP number of this address as an array of bytes |
* @param ipaddr The IP number of this address as an array of bytes |
202 |
* @param hostname The hostname of this IP address. |
* @param hostname The hostname of this IP address. |
|
* @param hostname_alias A backup hostname to use if hostname is null to |
|
|
* prevent reverse lookup failures |
|
203 |
*/ |
*/ |
204 |
InetAddress(byte[] ipaddr, String hostname, String hostname_alias) |
InetAddress(byte[] ipaddr, String hostname) |
205 |
{ |
{ |
206 |
addr = new byte[ipaddr.length]; |
addr = new byte[ipaddr.length]; |
207 |
|
|
209 |
addr[i] = ipaddr[i]; |
addr[i] = ipaddr[i]; |
210 |
|
|
211 |
this.hostName = hostname; |
this.hostName = hostname; |
|
this.hostname_alias = hostname_alias; |
|
212 |
lookup_time = System.currentTimeMillis(); |
lookup_time = System.currentTimeMillis(); |
213 |
|
|
214 |
family = 2; /* AF_INET */ |
family = 2; /* AF_INET */ |
|
address = addr[3] & 0xff; |
|
|
address |= ((addr[2] << 8) & 0xff00); |
|
|
address |= ((addr[1] << 16) & 0xff0000); |
|
|
address |= ((addr[0] << 24) & 0xff000000); |
|
215 |
} |
} |
216 |
|
|
217 |
/** |
/** |
382 |
} |
} |
383 |
catch (UnknownHostException e) |
catch (UnknownHostException e) |
384 |
{ |
{ |
385 |
if (hostname_alias != null) |
return getHostAddress(); |
|
return hostname_alias; |
|
|
else |
|
|
return getHostAddress(); |
|
386 |
} |
} |
387 |
} |
} |
388 |
|
|
389 |
/** |
/** |
390 |
|
* Returns the canonical hostname represented by this InetAddress |
391 |
|
* |
392 |
|
* @since 1.4 |
393 |
|
*/ |
394 |
|
public String getCanonicalHostName() |
395 |
|
{ |
396 |
|
SecurityManager sm = System.getSecurityManager(); |
397 |
|
if (sm != null) |
398 |
|
{ |
399 |
|
try |
400 |
|
{ |
401 |
|
sm.checkConnect(hostName, -1); |
402 |
|
} |
403 |
|
catch (SecurityException e) |
404 |
|
{ |
405 |
|
return getHostAddress(); |
406 |
|
} |
407 |
|
} |
408 |
|
|
409 |
|
// Try to find the FDQN now |
410 |
|
// FIXME: This does not work with IPv6. |
411 |
|
InetAddress address = new Inet4Address(getAddress(), null); |
412 |
|
return address.getHostName(); |
413 |
|
} |
414 |
|
|
415 |
|
/** |
416 |
* Returns the IP address of this object as a byte array. |
* Returns the IP address of this object as a byte array. |
417 |
* |
* |
418 |
* @return IP address |
* @return IP address |
436 |
{ |
{ |
437 |
StringBuffer sb = new StringBuffer(40); |
StringBuffer sb = new StringBuffer(40); |
438 |
|
|
439 |
for (int i = 0; i < addr.length; i++) |
int len = addr.length; |
440 |
|
int i = 0; |
441 |
|
|
442 |
|
for ( ; ; ) |
443 |
{ |
{ |
444 |
sb.append(addr[i] & 0xff); |
sb.append(addr[i] & 0xff); |
445 |
|
i++; |
446 |
if (i < (addr.length - 1)) |
|
447 |
sb.append("."); |
if (i == len) |
448 |
|
break; |
449 |
|
|
450 |
|
sb.append('.'); |
451 |
} |
} |
452 |
|
|
453 |
return sb.toString(); |
return sb.toString(); |
515 |
*/ |
*/ |
516 |
public String toString() |
public String toString() |
517 |
{ |
{ |
518 |
String host; |
String addr = getHostAddress(); |
519 |
String address = getHostAddress(); |
String host = (hostName != null) ? hostName : addr; |
520 |
|
return host + "/" + addr; |
|
if (hostName != null) |
|
|
host = hostName; |
|
|
else if (hostname_alias != null) |
|
|
host = hostname_alias; |
|
|
else |
|
|
host = address; |
|
|
|
|
|
return host + "/" + address; |
|
521 |
} |
} |
522 |
|
|
523 |
/** |
/** |
606 |
* default. This method is equivalent to returning the first element in |
* default. This method is equivalent to returning the first element in |
607 |
* the InetAddress array returned from GetAllByName. |
* the InetAddress array returned from GetAllByName. |
608 |
* |
* |
609 |
* @param hostname The name of the desired host, or null for the local machine. |
* @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. |
* @return The address of the host as an InetAddress object. |
613 |
* |
* |
619 |
public static InetAddress getByName(String hostname) |
public static InetAddress getByName(String hostname) |
620 |
throws UnknownHostException |
throws UnknownHostException |
621 |
{ |
{ |
|
SecurityManager s = System.getSecurityManager(); |
|
|
if (s != null) |
|
|
s.checkConnect(hostname, -1); |
|
|
|
|
|
// Default to current host if necessary |
|
|
if (hostname == null || hostname.length() == 0) |
|
|
return getLocalHost(); |
|
|
|
|
|
// Assume that the host string is an IP address |
|
|
byte[] address = aton(hostname); |
|
|
if (address != null) |
|
|
return new Inet4Address(address); |
|
|
|
|
|
// Try to resolve the host by DNS |
|
622 |
InetAddress[] addresses = getAllByName(hostname); |
InetAddress[] addresses = getAllByName(hostname); |
623 |
return addresses[0]; |
return addresses[0]; |
624 |
} |
} |
631 |
* hostname of the local machine is supplied by default. |
* hostname of the local machine is supplied by default. |
632 |
* |
* |
633 |
* @param hostname The name of the desired host, or null for the |
* @param hostname The name of the desired host, or null for the |
634 |
* local machine. |
* local loopback address. |
635 |
* |
* |
636 |
* @return All addresses of the host as an array of InetAddress objects. |
* @return All addresses of the host as an array of InetAddress objects. |
637 |
* |
* |
647 |
if (s != null) |
if (s != null) |
648 |
s.checkConnect(hostname, -1); |
s.checkConnect(hostname, -1); |
649 |
|
|
650 |
|
InetAddress[] addresses; |
651 |
|
|
652 |
// Default to current host if necessary |
// Default to current host if necessary |
653 |
if (hostname == null) |
if (hostname == null) |
654 |
{ |
{ |
655 |
InetAddress local = getLocalHost(); |
addresses = new InetAddress[1]; |
656 |
return getAllByName(local.getHostName()); |
addresses[0] = LOCALHOST; |
657 |
|
return addresses; |
658 |
} |
} |
659 |
|
|
660 |
// Check the cache for this host before doing a lookup |
// Check the cache for this host before doing a lookup |
661 |
InetAddress[] addresses = checkCacheFor(hostname); |
addresses = checkCacheFor(hostname); |
662 |
|
|
663 |
if (addresses != null) |
if (addresses != null) |
664 |
return addresses; |
return addresses; |
676 |
if (iplist[i].length != 4) |
if (iplist[i].length != 4) |
677 |
throw new UnknownHostException(hostname); |
throw new UnknownHostException(hostname); |
678 |
|
|
679 |
// Don't store the hostname in order to force resolution of the |
addresses[i] = new Inet4Address(iplist[i], hostname); |
|
// canonical names of these ip's when the user asks for the hostname |
|
|
// But do specify the host alias so if the IP returned won't |
|
|
// reverse lookup we don't throw an exception. |
|
|
addresses[i] = new Inet4Address(iplist[i], null, hostname); |
|
680 |
} |
} |
681 |
|
|
682 |
addToCache(hostname, addresses); |
addToCache(hostname, addresses); |
697 |
InetAddress[] addresses = null; |
InetAddress[] addresses = null; |
698 |
|
|
699 |
if (cache_size == 0) |
if (cache_size == 0) |
700 |
return (null); |
return null; |
701 |
|
|
702 |
Object obj = cache.get(hostname); |
Object obj = cache.get(hostname); |
703 |
if (obj == null) |
if (obj == null) |
704 |
return (null); |
return null; |
705 |
|
|
706 |
if (obj instanceof InetAddress[]) |
if (obj instanceof InetAddress[]) |
707 |
addresses = (InetAddress[]) obj; |
addresses = (InetAddress[]) obj; |
708 |
|
|
709 |
if (addresses == null) |
if (addresses == null) |
710 |
return (null); |
return null; |
711 |
|
|
712 |
if (cache_period != -1) |
if (cache_period != -1) |
713 |
if ((System.currentTimeMillis() - addresses[0].lookup_time) > cache_period) |
if ((System.currentTimeMillis() - addresses[0].lookup_time) > cache_period) |
714 |
{ |
{ |
715 |
cache.remove(hostname); |
cache.remove(hostname); |
716 |
return (null); |
return null; |
717 |
} |
} |
718 |
|
|
719 |
return addresses; |
return addresses; |
756 |
if (inaddr_any == null) |
if (inaddr_any == null) |
757 |
{ |
{ |
758 |
byte[] tmp = lookupInaddrAny(); |
byte[] tmp = lookupInaddrAny(); |
759 |
inaddr_any = new Inet4Address(tmp); |
inaddr_any = new Inet4Address(tmp, null); |
760 |
} |
} |
761 |
|
|
762 |
return inaddr_any; |
return inaddr_any; |