提交 334c0392 编写于 作者: R robm

7180557: InetAddress.getLocalHost throws UnknownHostException on java7u5 on OSX webbugs

Reviewed-by: chegar, dsamersoff
上级 ff2bca20
/* /*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -51,6 +51,24 @@ ...@@ -51,6 +51,24 @@
#define HAS_GLIBC_GETHOSTBY_R 1 #define HAS_GLIBC_GETHOSTBY_R 1
#endif #endif
static jclass ni_iacls;
static jclass ni_ia4cls;
static jmethodID ni_ia4ctrID;
static void initializeInetClasses(JNIEnv *env)
{
static int initialized = 0;
if (!initialized) {
ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
initialized = 1;
}
}
#if defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R) #if defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R)
/* Use getaddrinfo(3), which is thread safe */ /* Use getaddrinfo(3), which is thread safe */
/************************************************************************ /************************************************************************
...@@ -99,14 +117,6 @@ Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) { ...@@ -99,14 +117,6 @@ Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
return (*env)->NewStringUTF(env, hostname); return (*env)->NewStringUTF(env, hostname);
} }
static jclass ni_iacls;
static jclass ni_ia4cls;
static jmethodID ni_ia4ctrID;
static jfieldID ni_iaaddressID;
static jfieldID ni_iahostID;
static jfieldID ni_iafamilyID;
static int initialized = 0;
/* /*
* Find an internet address for a given hostname. Note that this * Find an internet address for a given hostname. Note that this
* code only works for addresses of type INET. The translation * code only works for addresses of type INET. The translation
...@@ -129,14 +139,7 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ...@@ -129,14 +139,7 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
int error=0; int error=0;
struct addrinfo hints, *res, *resNew = NULL; struct addrinfo hints, *res, *resNew = NULL;
if (!initialized) { initializeInetClasses(env);
ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
initialized = 1;
}
if (IS_NULL(host)) { if (IS_NULL(host)) {
JNU_ThrowNullPointerException(env, "host is null"); JNU_ThrowNullPointerException(env, "host is null");
...@@ -160,6 +163,17 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ...@@ -160,6 +163,17 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
return NULL; return NULL;
} }
#ifdef MACOSX
/* If we're looking up the local machine, bypass DNS lookups and get
* address from getifaddrs.
*/
ret = lookupIfLocalhost(env, hostname, JNI_FALSE);
if (ret != NULL || (*env)->ExceptionCheck(env)) {
JNU_ReleaseStringPlatformChars(env, host, hostname);
return ret;
}
#endif
error = getaddrinfo(hostname, NULL, &hints, &res); error = getaddrinfo(hostname, NULL, &hints, &res);
if (error) { if (error) {
...@@ -365,10 +379,7 @@ Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) { ...@@ -365,10 +379,7 @@ Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
return (*env)->NewStringUTF(env, hostname); return (*env)->NewStringUTF(env, hostname);
} }
static jclass ni_iacls; extern jobjectArray lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6);
static jclass ni_ia4cls;
static jmethodID ni_ia4ctrID;
static int initialized = 0;
/* /*
* Find an internet address for a given hostname. Note that this * Find an internet address for a given hostname. Note that this
...@@ -390,14 +401,7 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ...@@ -390,14 +401,7 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
int error = 0; int error = 0;
struct addrinfo hints, *res, *resNew = NULL; struct addrinfo hints, *res, *resNew = NULL;
if (!initialized) { initializeInetClasses(env);
ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
initialized = 1;
}
if (IS_NULL(host)) { if (IS_NULL(host)) {
JNU_ThrowNullPointerException(env, "host is null"); JNU_ThrowNullPointerException(env, "host is null");
......
/* /*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -33,7 +33,9 @@ ...@@ -33,7 +33,9 @@
#include <strings.h> #include <strings.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
#ifdef _ALLBSD_SOURCE #ifdef MACOSX
#include <ifaddrs.h>
#include <net/if.h>
#include <unistd.h> /* gethostname */ #include <unistd.h> /* gethostname */
#endif #endif
...@@ -121,7 +123,145 @@ static jclass ni_ia6cls; ...@@ -121,7 +123,145 @@ static jclass ni_ia6cls;
static jmethodID ni_ia4ctrID; static jmethodID ni_ia4ctrID;
static jmethodID ni_ia6ctrID; static jmethodID ni_ia6ctrID;
static jfieldID ni_ia6ipaddressID; static jfieldID ni_ia6ipaddressID;
static int initialized = 0;
static void initializeInetClasses(JNIEnv *env)
{
static int initialized = 0;
if (!initialized) {
ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
ni_ia6cls = (*env)->FindClass(env, "java/net/Inet6Address");
ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls);
ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V");
ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B");
initialized = 1;
}
}
#ifdef MACOSX
/* also called from Inet4AddressImpl.c */
__private_extern__ jobjectArray
lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6)
{
jobjectArray result = NULL;
jboolean preferIPv6Address;
char myhostname[NI_MAXHOST+1];
struct ifaddrs *ifa = NULL;
int familyOrder = 0;
int count = 0, i, j;
int addrs4 = 0, addrs6 = 0, numV4Loopbacks = 0, numV6Loopbacks = 0;
jboolean includeLoopback = JNI_FALSE;
jobject name;
// Make sure static variables we need are set.
initializeInetClasses(env);
/* get the address preference */
preferIPv6Address = (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID);
/* If the requested name matches this host's hostname, return IP addresses
* from all attached interfaces. (#2844683 et al) This prevents undesired
* PPP dialup, but may return addresses that don't actually correspond to
* the name (if the name actually matches something in DNS etc.
*/
myhostname[0] = '\0';
if (JVM_GetHostName(myhostname, NI_MAXHOST)) {
/* Something went wrong, maybe networking is not setup? */
return NULL;
}
myhostname[NI_MAXHOST] = '\0';
if (strcmp(myhostname, hostname) != 0) {
// Non-self lookup
return NULL;
}
if (getifaddrs(&ifa) != 0) {
NET_ThrowNew(env, errno, "Can't get local interface addresses");
return NULL;
}
name = (*env)->NewStringUTF(env, hostname);
/* Iterate over the interfaces, and total up the number of IPv4 and IPv6
* addresses we have. Also keep a count of loopback addresses. We need to
* exclude them in the normal case, but return them if we don't get an IP
* address.
*/
struct ifaddrs *iter = ifa;
while (iter) {
int family = iter->ifa_addr->sa_family;
if (iter->ifa_name[0] != '\0' && iter->ifa_addr)
{
jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
if (family == AF_INET) {
addrs4++;
if (isLoopback) numV4Loopbacks++;
} else if (family == AF_INET6 && includeV6) {
addrs6++;
if (isLoopback) numV6Loopbacks++;
} else {
/* We don't care e.g. AF_LINK */
}
}
iter = iter->ifa_next;
}
if (addrs4 == numV4Loopbacks && addrs6 == numV6Loopbacks) {
// We don't have a real IP address, just loopback. We need to include
// loopback in our results.
includeLoopback = JNI_TRUE;
}
/* Create and fill the Java array. */
int arraySize = addrs4 + addrs6 -
(includeLoopback ? 0 : (numV4Loopbacks + numV6Loopbacks));
result = (*env)->NewObjectArray(env, arraySize, ni_iacls, NULL);
if (!result) goto done;
if (preferIPv6Address) {
i = includeLoopback ? addrs6 : (addrs6 - numV6Loopbacks);
j = 0;
} else {
i = 0;
j = includeLoopback ? addrs4 : (addrs4 - numV4Loopbacks);
}
// Now loop around the ifaddrs
iter = ifa;
while (iter != NULL) {
jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
int family = iter->ifa_addr->sa_family;
if (iter->ifa_name[0] != '\0' && iter->ifa_addr
&& (family == AF_INET || (family == AF_INET6 && includeV6))
&& (!isLoopback || includeLoopback))
{
int port;
int index = (family == AF_INET) ? i++ : j++;
jobject o = NET_SockaddrToInetAddress(env, iter->ifa_addr, &port);
if (!o) {
freeifaddrs(ifa);
if (!(*env)->ExceptionCheck(env))
JNU_ThrowOutOfMemoryError(env, "Object allocation failed");
return NULL;
}
setInetAddress_hostName(env, o, name);
(*env)->SetObjectArrayElement(env, result, index, o);
(*env)->DeleteLocalRef(env, o);
}
iter = iter->ifa_next;
}
done:
freeifaddrs(ifa);
return result;
}
#endif
/* /*
* Find an internet address for a given hostname. Note that this * Find an internet address for a given hostname. Note that this
...@@ -147,18 +287,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ...@@ -147,18 +287,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
struct addrinfo hints, *res, *resNew = NULL; struct addrinfo hints, *res, *resNew = NULL;
#endif /* AF_INET6 */ #endif /* AF_INET6 */
if (!initialized) { initializeInetClasses(env);
ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
ni_ia6cls = (*env)->FindClass(env, "java/net/Inet6Address");
ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls);
ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V");
ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B");
initialized = 1;
}
if (IS_NULL(host)) { if (IS_NULL(host)) {
JNU_ThrowNullPointerException(env, "host is null"); JNU_ThrowNullPointerException(env, "host is null");
...@@ -167,6 +296,21 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ...@@ -167,6 +296,21 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE); hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
CHECK_NULL_RETURN(hostname, NULL); CHECK_NULL_RETURN(hostname, NULL);
#ifdef MACOSX
/*
* If getaddrinfo has failed and we're looking up the local machine, we
* attempt to get the address from getifaddrs. This ensures we get an
* IPv6 address for the local machine.
*/
if (error) {
ret = lookupIfLocalhost(env, hostname, JNI_TRUE);
if (ret != NULL || (*env)->ExceptionCheck(env)) {
JNU_ReleaseStringPlatformChars(env, host, hostname);
return ret;
}
}
#endif
#ifdef AF_INET6 #ifdef AF_INET6
static jfieldID ia_preferIPv6AddressID; static jfieldID ia_preferIPv6AddressID;
if (ia_preferIPv6AddressID == NULL) { if (ia_preferIPv6AddressID == NULL) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册