jdk/src/solaris/native/java/net/Inet4AddressImpl.c
changeset 12047 320a714614e9
parent 11278 ce6c46d16022
child 12688 f15fd32c975e
--- a/jdk/src/solaris/native/java/net/Inet4AddressImpl.c	Tue Mar 06 10:25:45 2012 +0800
+++ b/jdk/src/solaris/native/java/net/Inet4AddressImpl.c	Tue Mar 06 20:34:38 2012 +0000
@@ -36,12 +36,288 @@
 #include <stdlib.h>
 #include <ctype.h>
 
+#ifdef _ALLBSD_SOURCE
+#include <unistd.h>
+#include <sys/param.h>
+#endif
+
 #include "jvm.h"
 #include "jni_util.h"
 #include "net_util.h"
 
 #include "java_net_Inet4AddressImpl.h"
 
+#if defined(__GLIBC__) || (defined(__FreeBSD__) && (__FreeBSD_version >= 601104))
+#define HAS_GLIBC_GETHOSTBY_R   1
+#endif
+
+#if defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R)
+/* Use getaddrinfo(3), which is thread safe */
+/************************************************************************
+ * Inet4AddressImpl
+ */
+
+/*
+ * Class:     java_net_Inet4AddressImpl
+ * Method:    getLocalHostName
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
+    char hostname[NI_MAXHOST+1];
+
+    hostname[0] = '\0';
+    if (JVM_GetHostName(hostname, NI_MAXHOST)) {
+        /* Something went wrong, maybe networking is not setup? */
+        strcpy(hostname, "localhost");
+    } else {
+         struct addrinfo  hints, *res;
+         int error;
+
+         memset(&hints, 0, sizeof(hints));
+         hints.ai_flags = AI_CANONNAME;
+         hints.ai_family = AF_UNSPEC;
+
+         error = getaddrinfo(hostname, NULL, &hints, &res);
+
+         if (error == 0) {
+             /* host is known to name service */
+             error = getnameinfo(res->ai_addr,
+                                 res->ai_addrlen,
+                                 hostname,
+                                 NI_MAXHOST,
+                                 NULL,
+                                 0,
+                                 NI_NAMEREQD);
+
+             /* if getnameinfo fails hostname is still the value
+                from gethostname */
+
+             freeaddrinfo(res);
+        }
+    }
+    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
+ * 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
+ *
+ * Class:     java_net_Inet4AddressImpl
+ * Method:    lookupAllHostAddr
+ * Signature: (Ljava/lang/String;)[[B
+ */
+
+JNIEXPORT jobjectArray JNICALL
+Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
+                                                jstring host) {
+    const char *hostname;
+    jobject name;
+    jobjectArray ret = 0;
+    int retLen = 0;
+
+    int error=0;
+    struct addrinfo hints, *res, *resNew = NULL;
+
+    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");
+      ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I");
+      ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I");
+      ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;");
+      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);
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_CANONNAME;
+    hints.ai_family = AF_INET;
+
+    /*
+     * Workaround for Solaris bug 4160367 - if a hostname contains a
+     * white space then 0.0.0.0 is returned
+     */
+    if (isspace((unsigned char)hostname[0])) {
+        JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
+                        (char *)hostname);
+        JNU_ReleaseStringPlatformChars(env, host, hostname);
+        return NULL;
+    }
+
+    error = getaddrinfo(hostname, NULL, &hints, &res);
+
+    if (error) {
+        /* report error */
+        JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
+                        (char *)hostname);
+        JNU_ReleaseStringPlatformChars(env, host, hostname);
+        return NULL;
+    } else {
+        int i = 0;
+        struct addrinfo *itr, *last = NULL, *iterator = res;
+        while (iterator != NULL) {
+            int skip = 0;
+            itr = resNew;
+
+            while (itr != NULL) {
+                struct sockaddr_in *addr1, *addr2;
+
+                addr1 = (struct sockaddr_in *)iterator->ai_addr;
+                addr2 = (struct sockaddr_in *)itr->ai_addr;
+                if (addr1->sin_addr.s_addr ==
+                    addr2->sin_addr.s_addr) {
+                    skip = 1;
+                    break;
+                }
+
+                itr = itr->ai_next;
+            }
+
+            if (!skip) {
+                struct addrinfo *next
+                    = (struct addrinfo*) malloc(sizeof(struct addrinfo));
+                if (!next) {
+                    JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
+                    ret = NULL;
+                    goto cleanupAndReturn;
+                }
+                memcpy(next, iterator, sizeof(struct addrinfo));
+                next->ai_next = NULL;
+                if (resNew == NULL) {
+                    resNew = next;
+                } else {
+                    last->ai_next = next;
+                }
+                last = next;
+                i++;
+            }
+            iterator = iterator->ai_next;
+        }
+
+        retLen = i;
+        iterator = resNew;
+        i = 0;
+
+        name = (*env)->NewStringUTF(env, hostname);
+        if (IS_NULL(name)) {
+          goto cleanupAndReturn;
+        }
+
+        ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL);
+        if (IS_NULL(ret)) {
+            /* we may have memory to free at the end of this */
+            goto cleanupAndReturn;
+        }
+
+        while (iterator != NULL) {
+            /* We need 4 bytes to store ipv4 address; */
+            int len = 4;
+
+            jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
+            if (IS_NULL(iaObj)) {
+                /* we may have memory to free at the end of this */
+                ret = NULL;
+                goto cleanupAndReturn;
+            }
+            (*env)->SetIntField(env, iaObj, ni_iaaddressID,
+                                ntohl(((struct sockaddr_in*)(iterator->ai_addr))->sin_addr.s_addr));
+            (*env)->SetObjectField(env, iaObj, ni_iahostID, name);
+            (*env)->SetObjectArrayElement(env, ret, retLen - i -1, iaObj);
+            i++;
+            iterator = iterator->ai_next;
+        }
+    }
+
+cleanupAndReturn:
+    {
+        struct addrinfo *iterator, *tmp;
+        iterator = resNew;
+        while (iterator != NULL) {
+            tmp = iterator;
+            iterator = iterator->ai_next;
+            free(tmp);
+        }
+        JNU_ReleaseStringPlatformChars(env, host, hostname);
+    }
+
+    freeaddrinfo(res);
+
+    return ret;
+
+}
+
+/*
+ * Class:     java_net_Inet4AddressImpl
+ * Method:    getHostByAddr
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
+                                            jbyteArray addrArray) {
+    jstring ret = NULL;
+
+    char host[NI_MAXHOST+1];
+    jfieldID fid;
+    int error = 0;
+    jint family;
+    struct sockaddr *him ;
+    int len = 0;
+    jbyte caddr[4];
+    jint addr;
+
+    struct sockaddr_in him4;
+    struct sockaddr *sa;
+
+    /*
+         * For IPv4 addresses construct a sockaddr_in structure.
+         */
+    (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
+    addr = ((caddr[0]<<24) & 0xff000000);
+    addr |= ((caddr[1] <<16) & 0xff0000);
+    addr |= ((caddr[2] <<8) & 0xff00);
+    addr |= (caddr[3] & 0xff);
+    memset((char *) &him4, 0, sizeof(him4));
+    him4.sin_addr.s_addr = (uint32_t) htonl(addr);
+    him4.sin_family = AF_INET;
+    sa = (struct sockaddr *) &him4;
+    len = sizeof(him4);
+
+    error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
+                               NI_NAMEREQD);
+
+    if (!error) {
+        ret = (*env)->NewStringUTF(env, host);
+    }
+
+    if (ret == NULL) {
+        JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
+    }
+
+    return ret;
+
+}
+
+#else /* defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R) */
+
 /* the initial size of our hostent buffers */
 #ifndef NI_MAXHOST
 #define NI_MAXHOST 1025
@@ -292,6 +568,8 @@
     return ret;
 }
 
+#endif /* _ALLBSD_SOURCE */
+
 #define SET_NONBLOCKING(fd) {           \
         int flags = fcntl(fd, F_GETFL); \
         flags |= O_NONBLOCK;            \
@@ -430,6 +708,7 @@
 
     memset((char *) caddr, 0, sizeof(caddr));
     memset((char *) &him, 0, sizeof(him));
+    memset((char *) &inf, 0, sizeof(inf));
     sz = (*env)->GetArrayLength(env, addrArray);
     if (sz != 4) {
       return JNI_FALSE;