--- a/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c Mon Dec 19 17:09:10 2016 -0800
+++ b/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c Tue Dec 20 10:49:50 2016 +0100
@@ -113,24 +113,22 @@
* Class: java_net_Inet4AddressImpl
* Method: lookupAllHostAddr
* Signature: (Ljava/lang/String;)[[B
- *
- * This is almost shared code
*/
-
JNIEXPORT jobjectArray JNICALL
Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
- jstring host) {
+ jstring host) {
+ jobjectArray ret = NULL;
const char *hostname;
- struct hostent *hp;
+ int error = 0;
unsigned int addr[4];
-
- jobjectArray ret = NULL;
+ struct addrinfo hints, *res = NULL, *resNew = NULL, *last = NULL,
+ *iterator;
initInetAddressIDs(env);
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
if (IS_NULL(host)) {
- JNU_ThrowNullPointerException(env, "host argument");
+ JNU_ThrowNullPointerException(env, "host argument is null");
return NULL;
}
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
@@ -166,9 +164,9 @@
/*
* Return an byte array with the populated address.
*/
- address = (addr[3]<<24) & 0xff000000;
- address |= (addr[2]<<16) & 0xff0000;
- address |= (addr[1]<<8) & 0xff00;
+ address = (addr[3] << 24) & 0xff000000;
+ address |= (addr[2] << 16) & 0xff0000;
+ address |= (addr[1] << 8) & 0xff00;
address |= addr[0];
ret = (*env)->NewObjectArray(env, 1, ia_class, NULL);
@@ -179,58 +177,95 @@
iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
if (IS_NULL(iaObj)) {
- ret = NULL;
- goto cleanupAndReturn;
+ ret = NULL;
+ goto cleanupAndReturn;
}
setInetAddress_addr(env, iaObj, ntohl(address));
(*env)->SetObjectArrayElement(env, ret, 0, iaObj);
- JNU_ReleaseStringPlatformChars(env, host, hostname);
- return ret;
+ goto cleanupAndReturn;
}
- /*
- * Perform the lookup
- */
- if ((hp = gethostbyname((char*)hostname)) != NULL) {
- struct in_addr **addrp = (struct in_addr **) hp->h_addr_list;
- int len = sizeof(struct in_addr);
+ // try once, with our static buffer
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_INET;
+
+ error = getaddrinfo(hostname, NULL, &hints, &res);
+
+ if (error) {
+ NET_ThrowByNameWithLastError(env, "java/net/UnknownHostException",
+ hostname);
+ goto cleanupAndReturn;
+ } else {
int i = 0;
+ iterator = res;
+ while (iterator != NULL) {
+ // skip duplicates
+ int skip = 0;
+ struct addrinfo *iteratorNew = resNew;
+ while (iteratorNew != NULL) {
+ struct sockaddr_in *addr1, *addr2;
+ addr1 = (struct sockaddr_in *)iterator->ai_addr;
+ addr2 = (struct sockaddr_in *)iteratorNew->ai_addr;
+ if (addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) {
+ skip = 1;
+ break;
+ }
+ iteratorNew = iteratorNew->ai_next;
+ }
- while (*addrp != (struct in_addr *) 0) {
- i++;
- addrp++;
+ if (!skip) {
+ struct addrinfo *next
+ = (struct addrinfo *)malloc(sizeof(struct addrinfo));
+ if (!next) {
+ JNU_ThrowOutOfMemoryError(env, "Native 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;
}
+ // allocate array - at this point i contains the number of addresses
ret = (*env)->NewObjectArray(env, i, ia_class, NULL);
-
if (IS_NULL(ret)) {
goto cleanupAndReturn;
}
- addrp = (struct in_addr **) hp->h_addr_list;
i = 0;
- while (*addrp != (struct in_addr *) 0) {
- jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
- if (IS_NULL(iaObj)) {
- ret = NULL;
- goto cleanupAndReturn;
- }
- setInetAddress_addr(env, iaObj, ntohl((*addrp)->s_addr));
- setInetAddress_hostName(env, iaObj, host);
- (*env)->SetObjectArrayElement(env, ret, i, iaObj);
- addrp++;
- i++;
+ iterator = resNew;
+ while (iterator != NULL) {
+ jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
+ if (IS_NULL(iaObj)) {
+ ret = NULL;
+ goto cleanupAndReturn;
+ }
+ setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in *)
+ (iterator->ai_addr))->sin_addr.s_addr));
+ setInetAddress_hostName(env, iaObj, host);
+ (*env)->SetObjectArrayElement(env, ret, i++, iaObj);
+ iterator = iterator->ai_next;
}
- } else if (WSAGetLastError() == WSATRY_AGAIN) {
- NET_ThrowByNameWithLastError(env,
- JNU_JAVANETPKG "UnknownHostException",
- hostname);
- } else {
- JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", hostname);
}
-
cleanupAndReturn:
JNU_ReleaseStringPlatformChars(env, host, hostname);
+ while (resNew != NULL) {
+ last = resNew;
+ resNew = resNew->ai_next;
+ free(last);
+ }
+ if (res != NULL) {
+ freeaddrinfo(res);
+ }
return ret;
}
@@ -238,30 +273,42 @@
* Class: java_net_Inet4AddressImpl
* Method: getHostByAddr
* Signature: (I)Ljava/lang/String;
+ *
+ * Theoretically the UnknownHostException could be enriched with gai error
+ * information. But as it is silently ignored anyway, there's no need for this.
+ * It's only important that either a valid hostname is returned or an
+ * UnknownHostException is thrown.
*/
JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
- jbyteArray addrArray) {
- struct hostent *hp;
+ jbyteArray addrArray) {
+ jstring ret = NULL;
+ char host[NI_MAXHOST + 1];
jbyte caddr[4];
jint addr;
+ struct sockaddr_in sa;
+
+ // construct a sockaddr_in structure
+ memset((char *)&sa, 0, sizeof(struct sockaddr_in));
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
- addr = ((caddr[0]<<24) & 0xff000000);
- addr |= ((caddr[1] <<16) & 0xff0000);
- addr |= ((caddr[2] <<8) & 0xff00);
+ addr = ((caddr[0] << 24) & 0xff000000);
+ addr |= ((caddr[1] << 16) & 0xff0000);
+ addr |= ((caddr[2] << 8) & 0xff00);
addr |= (caddr[3] & 0xff);
- addr = htonl(addr);
+ sa.sin_addr.s_addr = htonl(addr);
+ sa.sin_family = AF_INET;
- hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
- if (hp == NULL) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 0);
- return NULL;
+ if (getnameinfo((struct sockaddr *)&sa, sizeof(struct sockaddr_in),
+ host, NI_MAXHOST, NULL, 0, NI_NAMEREQD)) {
+ JNU_ThrowByName(env, "java/net/UnknownHostException", NULL);
+ } else {
+ ret = (*env)->NewStringUTF(env, host);
+ if (ret == NULL) {
+ JNU_ThrowByName(env, "java/net/UnknownHostException", NULL);
+ }
}
- if (hp->h_name == NULL) { /* Deal with bug in Windows XP */
- JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 0);
- return NULL;
- }
- return JNU_NewStringPlatform(env, hp->h_name);
+
+ return ret;
}
static jboolean