src/solaris/native/java/net/Inet6AddressImpl.c
Print this page
*** 31,41 ****
#include <netdb.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <ctype.h>
! #ifdef _ALLBSD_SOURCE
#include <unistd.h> /* gethostname */
#endif
#include "jvm.h"
#include "jni_util.h"
--- 31,43 ----
#include <netdb.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <ctype.h>
! #ifdef MACOSX
! #include <ifaddrs.h>
! #include <net/if.h>
#include <unistd.h> /* gethostname */
#endif
#include "jvm.h"
#include "jni_util.h"
*** 121,130 ****
--- 123,282 ----
static jmethodID ni_ia4ctrID;
static jmethodID ni_ia6ctrID;
static jfieldID ni_ia6ipaddressID;
static int initialized = 0;
+ static void initializeInetClasses(JNIEnv *env)
+ {
+ 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[MAXHOSTNAMELEN+1];
+ struct ifaddrs *ifa = NULL;
+ int familyOrder = 0;
+ int count = 0, i;
+ int addrs4 = 0, addrs6 = 0, numLoopbacks = 0;
+ jboolean includeLoopback = JNI_FALSE;
+ jobject name;
+
+ // Make sure static variables we need are set.
+ if (!initialized) 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';
+ JVM_GetHostName(myhostname, MAXHOSTNAMELEN);
+ myhostname[MAXHOSTNAMELEN] = '\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) numLoopbacks++;
+ } else if (family == AF_INET6 && includeV6) {
+ addrs6++;
+ if (isLoopback) numLoopbacks++;
+ } else {
+ /* We don't care e.g. AF_LINK */
+ }
+ }
+ iter = iter->ifa_next;
+ }
+
+ if (addrs4 == 1) {
+ // 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 : numLoopbacks);
+ result = (*env)->NewObjectArray(env, arraySize, ni_iacls, NULL); // AWT_THREADING Safe (known object)
+ if (!result) goto done;
+
+ if (preferIPv6Address) {
+ familyOrder = 1;
+ }
+
+ /* Now we iterate twice over the list, once for IPv4 addresses and once for
+ * IPv6 addresses. preferIPv6Address property decides for us which
+ * addresses to look for first - IPv4 or IPv6. The familyOrder mod'ding
+ * helps reduce code a bit.
+ */
+ for (i = 0; i < 2; i++, familyOrder++) {
+ int family;
+ if (familyOrder % 2)
+ family = AF_INET6;
+ else
+ family = AF_INET;
+
+ if (family == AF_INET6 && !includeV6)
+ continue; // No need to send back IPv6 addresses
+
+ // Now loop around the ifaddrs
+ iter = ifa;
+ while (iter != NULL) {
+ if (iter->ifa_name[0] != '\0' && iter->ifa_addr &&
+ (family == iter->ifa_addr->sa_family))
+ {
+ jboolean addAddress = JNI_FALSE;
+ jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
+
+ // Non-loopback addresses always get added
+ if (!isLoopback)
+ addAddress = JNI_TRUE;
+
+ // If we're a loopback address, we need to add it only if
+ // includeLoopback is set
+ if (isLoopback && includeLoopback)
+ addAddress = JNI_TRUE;
+
+ if (addAddress) {
+ int port;
+ jobject o = NET_SockaddrToInetAddress(env, iter->ifa_addr, &port);
+ if (!o) goto done; // object allocation failed
+ (*env)->SetObjectArrayElement(env, result, count, o);
+ (*env)->DeleteLocalRef(env, o);
+ count++;
+ }
+ }
+ iter = iter->ifa_next;
+ }
+ }
+
+ done:
+ freeifaddrs(ifa);
+
+ return result;
+ }
+ #endif
+
/*
* 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
*** 145,174 ****
int error=0;
#ifdef AF_INET6
struct addrinfo hints, *res, *resNew = NULL;
#endif /* AF_INET6 */
! 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;
! }
if (IS_NULL(host)) {
JNU_ThrowNullPointerException(env, "host is null");
return 0;
}
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
CHECK_NULL_RETURN(hostname, NULL);
#ifdef AF_INET6
static jfieldID ia_preferIPv6AddressID;
if (ia_preferIPv6AddressID == NULL) {
jclass c = (*env)->FindClass(env,"java/net/InetAddress");
if (c) {
--- 297,327 ----
int error=0;
#ifdef AF_INET6
struct addrinfo hints, *res, *resNew = NULL;
#endif /* AF_INET6 */
! if (!initialized) initializeInetClasses(env);
if (IS_NULL(host)) {
JNU_ThrowNullPointerException(env, "host is null");
return 0;
}
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
CHECK_NULL_RETURN(hostname, NULL);
+ #ifdef MACOSX
+ /* If we're looking up the local machine, bypass DNS lookups and get
+ * address from getifaddrs. This ensures we get an IPv6 address for the
+ * local machine.
+ */
+ ret = lookupIfLocalhost(env, hostname, JNI_TRUE);
+ if (ret != NULL) {
+ JNU_ReleaseStringPlatformChars(env, host, hostname);
+ return ret;
+ }
+ #endif
+
#ifdef AF_INET6
static jfieldID ia_preferIPv6AddressID;
if (ia_preferIPv6AddressID == NULL) {
jclass c = (*env)->FindClass(env,"java/net/InetAddress");
if (c) {