提交 82d31a26 编写于 作者: M martin

6981157: Improve UnknownHostException with EAI error details and other cleanups

Summary: generify; remove compiler warnings, typos, casts; return status information via gai_strerror when getaddrinfo fails; show full stack of native failures
Reviewed-by: michaelm, alanb
上级 4a120b94
......@@ -677,19 +677,20 @@ class InetAddress implements java.io.Serializable {
static InetAddressImpl impl;
private static HashMap lookupTable = new HashMap();
private static HashMap<String, InetAddress[]> lookupTable
= new HashMap<String, InetAddress[]>();
/**
* Represents a cache entry
*/
static final class CacheEntry {
CacheEntry(Object address, long expiration) {
this.address = address;
CacheEntry(InetAddress[] addresses, long expiration) {
this.addresses = addresses;
this.expiration = expiration;
}
Object address;
InetAddress[] addresses;
long expiration;
}
......@@ -698,7 +699,7 @@ class InetAddress implements java.io.Serializable {
* at creation time.
*/
static final class Cache {
private LinkedHashMap cache;
private LinkedHashMap<String, CacheEntry> cache;
private Type type;
enum Type {Positive, Negative};
......@@ -708,7 +709,7 @@ class InetAddress implements java.io.Serializable {
*/
public Cache(Type type) {
this.type = type;
cache = new LinkedHashMap();
cache = new LinkedHashMap<String, CacheEntry>();
}
private int getPolicy() {
......@@ -724,7 +725,7 @@ class InetAddress implements java.io.Serializable {
* entry then for this host then the entry will be
* replaced.
*/
public Cache put(String host, Object address) {
public Cache put(String host, InetAddress[] addresses) {
int policy = getPolicy();
if (policy == InetAddressCachePolicy.NEVER) {
return this;
......@@ -736,12 +737,10 @@ class InetAddress implements java.io.Serializable {
// As we iterate in insertion order we can
// terminate when a non-expired entry is found.
LinkedList expired = new LinkedList();
Iterator i = cache.keySet().iterator();
LinkedList<String> expired = new LinkedList<String>();
long now = System.currentTimeMillis();
while (i.hasNext()) {
String key = (String)i.next();
CacheEntry entry = (CacheEntry)cache.get(key);
for (String key : cache.keySet()) {
CacheEntry entry = cache.get(key);
if (entry.expiration >= 0 && entry.expiration < now) {
expired.add(key);
......@@ -750,9 +749,8 @@ class InetAddress implements java.io.Serializable {
}
}
i = expired.iterator();
while (i.hasNext()) {
cache.remove(i.next());
for (String key : expired) {
cache.remove(key);
}
}
......@@ -766,7 +764,7 @@ class InetAddress implements java.io.Serializable {
} else {
expiration = System.currentTimeMillis() + (policy * 1000);
}
CacheEntry entry = new CacheEntry(address, expiration);
CacheEntry entry = new CacheEntry(addresses, expiration);
cache.put(host, entry);
return this;
}
......@@ -780,7 +778,7 @@ class InetAddress implements java.io.Serializable {
if (policy == InetAddressCachePolicy.NEVER) {
return null;
}
CacheEntry entry = (CacheEntry)cache.get(host);
CacheEntry entry = cache.get(host);
// check if entry has expired
if (entry != null && policy != InetAddressCachePolicy.FOREVER) {
......@@ -814,42 +812,41 @@ class InetAddress implements java.io.Serializable {
}
/*
* Cache the given hostname and address.
* Cache the given hostname and addresses.
*/
private static void cacheAddress(String hostname, Object address,
boolean success) {
private static void cacheAddresses(String hostname,
InetAddress[] addresses,
boolean success) {
hostname = hostname.toLowerCase();
synchronized (addressCache) {
cacheInitIfNeeded();
if (success) {
addressCache.put(hostname, address);
addressCache.put(hostname, addresses);
} else {
negativeCache.put(hostname, address);
negativeCache.put(hostname, addresses);
}
}
}
/*
* Lookup hostname in cache (positive & negative cache). If
* found return address, null if not found.
* found return addresses, null if not found.
*/
private static Object getCachedAddress(String hostname) {
private static InetAddress[] getCachedAddresses(String hostname) {
hostname = hostname.toLowerCase();
// search both positive & negative caches
synchronized (addressCache) {
CacheEntry entry;
cacheInitIfNeeded();
entry = addressCache.get(hostname);
CacheEntry entry = addressCache.get(hostname);
if (entry == null) {
entry = negativeCache.get(hostname);
}
if (entry != null) {
return entry.address;
return entry.addresses;
}
}
......@@ -911,7 +908,7 @@ class InetAddress implements java.io.Serializable {
static {
// create the impl
impl = (new InetAddressImplFactory()).create();
impl = InetAddressImplFactory.create();
// get name service if provided and requested
String provider = null;;
......@@ -931,7 +928,7 @@ class InetAddress implements java.io.Serializable {
}
// if not designate any name services provider,
// creat a default one
// create a default one
if (nameServices.size() == 0) {
NameService ns = createNSProvider("default");
nameServices.add(ns);
......@@ -939,7 +936,7 @@ class InetAddress implements java.io.Serializable {
}
/**
* Create an InetAddress based on the provided host name and IP address
* Creates an InetAddress based on the provided host name and IP address.
* No name service is checked for the validity of the address.
*
* <p> The host name can either be a machine name, such as
......@@ -1067,13 +1064,13 @@ class InetAddress implements java.io.Serializable {
boolean ipv6Expected = false;
if (host.charAt(0) == '[') {
// This is supposed to be an IPv6 litteral
// This is supposed to be an IPv6 literal
if (host.length() > 2 && host.charAt(host.length()-1) == ']') {
host = host.substring(1, host.length() -1);
ipv6Expected = true;
} else {
// This was supposed to be a IPv6 address, but it's not!
throw new UnknownHostException(host);
throw new UnknownHostException(host + ": invalid IPv6 address");
}
}
......@@ -1180,8 +1177,6 @@ class InetAddress implements java.io.Serializable {
throws UnknownHostException {
/* If it gets here it is presumed to be a hostname */
/* Cache.get can return: null, unknownAddress, or InetAddress[] */
Object obj = null;
Object objcopy = null;
/* make sure the connection to the host is allowed, before we
* give out a hostname
......@@ -1193,26 +1188,23 @@ class InetAddress implements java.io.Serializable {
}
}
obj = getCachedAddress(host);
InetAddress[] addresses = getCachedAddresses(host);
/* If no entry in cache, then do the host lookup */
if (obj == null) {
obj = getAddressFromNameService(host);
if (addresses == null) {
addresses = getAddressesFromNameService(host);
}
if (obj == unknown_array)
if (addresses == unknown_array)
throw new UnknownHostException(host);
/* Make a copy of the InetAddress array */
objcopy = ((InetAddress [])obj).clone();
return (InetAddress [])objcopy;
return addresses.clone();
}
private static Object getAddressFromNameService(String host)
private static InetAddress[] getAddressesFromNameService(String host)
throws UnknownHostException
{
Object obj = null;
InetAddress[] addresses = null;
boolean success = false;
UnknownHostException ex = null;
......@@ -1226,16 +1218,16 @@ class InetAddress implements java.io.Serializable {
// would be blocked until the host is removed
// from the lookupTable. Then this thread
// should try to look up the addressCache.
// i) if it found the address in the
// i) if it found the addresses in the
// addressCache, checkLookupTable() would
// return the address.
// ii) if it didn't find the address in the
// return the addresses.
// ii) if it didn't find the addresses in the
// addressCache for any reason,
// it should add the host in the
// lookupTable and return null so the
// following code would do a lookup itself.
if ((obj = checkLookupTable(host)) == null) {
// This is the first thread which looks up the address
if ((addresses = checkLookupTable(host)) == null) {
// This is the first thread which looks up the addresses
// this host or the cache entry for this host has been
// expired so this thread should do the lookup.
for (NameService nameService : nameServices) {
......@@ -1246,26 +1238,26 @@ class InetAddress implements java.io.Serializable {
* allocating space when the lookup fails.
*/
obj = nameService.lookupAllHostAddr(host);
addresses = nameService.lookupAllHostAddr(host);
success = true;
break;
} catch (UnknownHostException uhe) {
if (host.equalsIgnoreCase("localhost")) {
InetAddress[] local = new InetAddress[] { impl.loopbackAddress() };
obj = local;
addresses = local;
success = true;
break;
}
else {
obj = unknown_array;
addresses = unknown_array;
success = false;
ex = uhe;
}
}
}
// Cache the address.
cacheAddress(host, obj, success);
// Cache the addresses.
cacheAddresses(host, addresses, success);
// Delete the host from the lookupTable, and
// notify all threads waiting for the monitor
// for lookupTable.
......@@ -1274,13 +1266,13 @@ class InetAddress implements java.io.Serializable {
throw ex;
}
return obj;
return addresses;
}
private static Object checkLookupTable(String host) {
// make sure obj is null.
Object obj = null;
private static InetAddress[] checkLookupTable(String host) {
// make sure addresses is null.
InetAddress[] addresses = null;
synchronized (lookupTable) {
// If the host isn't in the lookupTable, add it in the
......@@ -1288,11 +1280,11 @@ class InetAddress implements java.io.Serializable {
// the lookup.
if (lookupTable.containsKey(host) == false) {
lookupTable.put(host, null);
return obj;
return addresses;
}
// If the host is in the lookupTable, it means that another
// thread is trying to look up the address of this host.
// thread is trying to look up the addresses of this host.
// This thread should wait.
while (lookupTable.containsKey(host)) {
try {
......@@ -1302,18 +1294,18 @@ class InetAddress implements java.io.Serializable {
}
}
// The other thread has finished looking up the address of
// the host. This thread should retry to get the address
// from the addressCache. If it doesn't get the address from
// the cache, it will try to look up the address itself.
obj = getCachedAddress(host);
if (obj == null) {
// The other thread has finished looking up the addresses of
// the host. This thread should retry to get the addresses
// from the addressCache. If it doesn't get the addresses from
// the cache, it will try to look up the addresses itself.
addresses = getCachedAddresses(host);
if (addresses == null) {
synchronized (lookupTable) {
lookupTable.put(host, null);
}
}
return obj;
return addresses;
}
private static void updateLookupTable(String host) {
......@@ -1396,15 +1388,20 @@ class InetAddress implements java.io.Serializable {
cachedLocalHost = null;
}
// we are calling getAddressFromNameService directly
// we are calling getAddressesFromNameService directly
// to avoid getting localHost from cache
if (ret == null) {
InetAddress[] localAddrs;
try {
localAddrs =
(InetAddress[]) InetAddress.getAddressFromNameService(local);
InetAddress.getAddressesFromNameService(local);
} catch (UnknownHostException uhe) {
throw new UnknownHostException(local + ": " + uhe.getMessage());
// Rethrow with a more informative error message.
UnknownHostException uhe2 =
new UnknownHostException(local + ": " +
uhe.getMessage());
uhe2.initCause(uhe);
throw uhe2;
}
cachedLocalHost = localAddrs[0];
cacheTime = now;
......@@ -1434,8 +1431,8 @@ class InetAddress implements java.io.Serializable {
/*
* Load and instantiate an underlying impl class
*/
static Object loadImpl(String implName) {
Object impl;
static InetAddressImpl loadImpl(String implName) {
Object impl = null;
/*
* Property "impl.prefix" will be prepended to the classname
......@@ -1446,7 +1443,6 @@ class InetAddress implements java.io.Serializable {
*/
String prefix = AccessController.doPrivileged(
new GetPropertyAction("impl.prefix", ""));
impl = null;
try {
impl = Class.forName("java.net." + prefix + implName).newInstance();
} catch (ClassNotFoundException e) {
......@@ -1471,7 +1467,7 @@ class InetAddress implements java.io.Serializable {
}
}
return impl;
return (InetAddressImpl) impl;
}
private void readObjectNoData (ObjectInputStream s) throws
......@@ -1498,13 +1494,8 @@ class InetAddress implements java.io.Serializable {
class InetAddressImplFactory {
static InetAddressImpl create() {
Object o;
if (isIPv6Supported()) {
o = InetAddress.loadImpl("Inet6AddressImpl");
} else {
o = InetAddress.loadImpl("Inet4AddressImpl");
}
return (InetAddressImpl)o;
return InetAddress.loadImpl(isIPv6Supported() ?
"Inet6AddressImpl" : "Inet4AddressImpl");
}
static native boolean isIPv6Supported();
......
......@@ -124,7 +124,7 @@ static jfieldID ni_ia6ipaddressID;
static int initialized = 0;
/*
* Find an internet address for a given hostname. Not this this
* Find an internet address for a given hostname. Note that this
* code only works for addresses of type INET. The translation
* of %d.%d.%d.%d to an address (int) occurs in java now, so the
* String "host" shouldn't *ever* be a %d.%d.%d.%d string
......@@ -200,7 +200,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
*/
if (isspace((unsigned char)hostname[0])) {
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
(char *)hostname);
hostname);
JNU_ReleaseStringPlatformChars(env, host, hostname);
return NULL;
}
......@@ -210,8 +210,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
if (error) {
/* report error */
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
(char *)hostname);
ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
JNU_ReleaseStringPlatformChars(env, host, hostname);
return NULL;
} else {
......@@ -407,7 +406,7 @@ Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
addr |= ((caddr[1] <<16) & 0xff0000);
addr |= ((caddr[2] <<8) & 0xff00);
addr |= (caddr[3] & 0xff);
memset((char *) &him4, 0, sizeof(him4));
memset((void *) &him4, 0, sizeof(him4));
him4.sin_addr.s_addr = (uint32_t) htonl(addr);
him4.sin_family = AF_INET;
sa = (struct sockaddr *) &him4;
......@@ -417,7 +416,7 @@ Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
* For IPv6 address construct a sockaddr_in6 structure.
*/
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
memset((char *) &him6, 0, sizeof(him6));
memset((void *) &him6, 0, sizeof(him6));
memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
him6.sin6_family = AF_INET6;
sa = (struct sockaddr *) &him6 ;
......@@ -579,8 +578,8 @@ Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this,
ifArray, ttl);
}
memset((char *) caddr, 0, 16);
memset((char *) &him6, 0, sizeof(him6));
memset((void *) caddr, 0, 16);
memset((void *) &him6, 0, sizeof(him6));
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
him6.sin6_family = AF_INET6;
......@@ -600,8 +599,8 @@ Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this,
* for it.
*/
if (!(IS_NULL(ifArray))) {
memset((char *) caddr, 0, 16);
memset((char *) &inf6, 0, sizeof(inf6));
memset((void *) caddr, 0, 16);
memset((void *) &inf6, 0, sizeof(inf6));
(*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr);
memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) );
inf6.sin6_family = AF_INET6;
......
......@@ -61,6 +61,7 @@
getaddrinfo_f getaddrinfo_ptr = NULL;
freeaddrinfo_f freeaddrinfo_ptr = NULL;
gai_strerror_f gai_strerror_ptr = NULL;
getnameinfo_f getnameinfo_ptr = NULL;
/*
......@@ -342,11 +343,14 @@ jint IPv6_supported()
freeaddrinfo_ptr = (freeaddrinfo_f)
JVM_FindLibraryEntry(RTLD_DEFAULT, "freeaddrinfo");
gai_strerror_ptr = (gai_strerror_f)
JVM_FindLibraryEntry(RTLD_DEFAULT, "gai_strerror");
getnameinfo_ptr = (getnameinfo_f)
JVM_FindLibraryEntry(RTLD_DEFAULT, "getnameinfo");
if (freeaddrinfo_ptr == NULL || getnameinfo_ptr == NULL) {
/* Wee need all 3 of them */
/* We need all 3 of them */
getaddrinfo_ptr = NULL;
}
......@@ -355,6 +359,32 @@ jint IPv6_supported()
#endif /* AF_INET6 */
}
void ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
const char* hostname,
int gai_error)
{
const char *format = "%s: %s";
const char *error_string =
(gai_strerror_ptr == NULL) ? NULL : (*gai_strerror_ptr)(gai_error);
if (error_string == NULL)
error_string = "unknown error";
int size = strlen(format) + strlen(hostname) + strlen(error_string) + 2;
char *buf = (char *) malloc(size);
if (buf) {
sprintf(buf, format, hostname, error_string);
jstring s = JNU_NewStringPlatform(env, buf);
if (s != NULL) {
jobject x = JNU_NewObjectByName(env,
"java/net/UnknownHostException",
"(Ljava/lang/String;)V", s);
if (x != NULL)
(*env)->Throw(env, x);
}
free(buf);
}
}
void
NET_AllocSockaddr(struct sockaddr **him, int *len) {
#ifdef AF_INET6
......
......@@ -84,11 +84,13 @@ int getDefaultIPv6Interface(struct in6_addr *target_addr);
/* needed from libsocket on Solaris 8 */
typedef int (*getaddrinfo_f)(const char *nodename, const char *servname,
const struct addrinfo *hints, struct addrinfo **res);
typedef int (*getaddrinfo_f)(const char *nodename, const char *servname,
const struct addrinfo *hints, struct addrinfo **res);
typedef void (*freeaddrinfo_f)(struct addrinfo *);
typedef const char * (*gai_strerror_f)(int ecode);
typedef int (*getnameinfo_f)(const struct sockaddr *, size_t,
char *, size_t, char *, size_t, int);
......@@ -96,6 +98,10 @@ extern getaddrinfo_f getaddrinfo_ptr;
extern freeaddrinfo_f freeaddrinfo_ptr;
extern getnameinfo_f getnameinfo_ptr;
void ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
const char* hostname,
int gai_error);
/* do we have address translation support */
extern jboolean NET_addrtransAvailable();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册