mirror of
https://github.com/openjdk/jdk.git
synced 2026-06-08 03:25:05 +00:00
7112670: Inet4AddressImpl should use getaddrinfo/getnameinfo
Reviewed-by: chegar, alanb, mduigou, ngmr
This commit is contained in:
parent
dbdf12e6a5
commit
5f797b5bda
@ -43,8 +43,9 @@
|
||||
#include "java_net_Inet4AddressImpl.h"
|
||||
|
||||
/* the initial size of our hostent buffers */
|
||||
#define HENT_BUF_SIZE 1024
|
||||
#define BIG_HENT_BUF_SIZE 10240 /* a jumbo-sized one */
|
||||
#ifndef NI_MAXHOST
|
||||
#define NI_MAXHOST 1025
|
||||
#endif
|
||||
|
||||
/************************************************************************
|
||||
* Inet4AddressImpl
|
||||
@ -57,60 +58,36 @@
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
char hostname[NI_MAXHOST+1];
|
||||
|
||||
hostname[0] = '\0';
|
||||
if (JVM_GetHostName(hostname, sizeof(hostname))) {
|
||||
/* Something went wrong, maybe networking is not setup? */
|
||||
strcpy(hostname, "localhost");
|
||||
} else {
|
||||
#ifdef __linux__
|
||||
/* On Linux gethostname() says "host.domain.sun.com". On
|
||||
* Solaris gethostname() says "host", so extra work is needed.
|
||||
*/
|
||||
#else
|
||||
/* Solaris doesn't want to give us a fully qualified domain name.
|
||||
* We do a reverse lookup to try and get one. This works
|
||||
* if DNS occurs before NIS in /etc/resolv.conf, but fails
|
||||
* if NIS comes first (it still gets only a partial name).
|
||||
* We use thread-safe system calls.
|
||||
*/
|
||||
#endif /* __linux__ */
|
||||
struct hostent res, res2, *hp;
|
||||
// these buffers must be pointer-aligned so they are declared
|
||||
// with pointer type
|
||||
char *buf[HENT_BUF_SIZE/(sizeof (char *))];
|
||||
char *buf2[HENT_BUF_SIZE/(sizeof (char *))];
|
||||
int h_error=0;
|
||||
hostname[NI_MAXHOST] = '\0';
|
||||
struct addrinfo hints, *res;
|
||||
int error;
|
||||
|
||||
// ensure null-terminated
|
||||
hostname[MAXHOSTNAMELEN] = '\0';
|
||||
bzero(&hints, sizeof(hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_family = AF_INET;
|
||||
|
||||
#ifdef __GLIBC__
|
||||
gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &hp, &h_error);
|
||||
#else
|
||||
hp = gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &h_error);
|
||||
#endif
|
||||
if (hp) {
|
||||
#ifdef __GLIBC__
|
||||
gethostbyaddr_r(hp->h_addr, hp->h_length, AF_INET,
|
||||
&res2, (char*)buf2, sizeof(buf2), &hp, &h_error);
|
||||
#else
|
||||
hp = gethostbyaddr_r(hp->h_addr, hp->h_length, AF_INET,
|
||||
&res2, (char*)buf2, sizeof(buf2), &h_error);
|
||||
#endif
|
||||
if (hp) {
|
||||
/*
|
||||
* If gethostbyaddr_r() found a fully qualified host name,
|
||||
* returns that name. Otherwise, returns the hostname
|
||||
* found by gethostname().
|
||||
*/
|
||||
char *p = hp->h_name;
|
||||
if ((strlen(hp->h_name) > strlen(hostname))
|
||||
&& (strncmp(hostname, hp->h_name, strlen(hostname)) == 0)
|
||||
&& (*(p + strlen(hostname)) == '.'))
|
||||
strcpy(hostname, hp->h_name);
|
||||
}
|
||||
error = getaddrinfo(hostname, NULL, &hints, &res);
|
||||
|
||||
if (error == 0) {/* host is known to name service */
|
||||
getnameinfo(res->ai_addr,
|
||||
res->ai_addrlen,
|
||||
hostname,
|
||||
MAXHOSTNAMELEN,
|
||||
NULL,
|
||||
0,
|
||||
NI_NAMEREQD);
|
||||
|
||||
/* if getnameinfo fails hostname is still the value
|
||||
from gethostname */
|
||||
|
||||
freeaddrinfo(res);
|
||||
}
|
||||
}
|
||||
return (*env)->NewStringUTF(env, hostname);
|
||||
@ -140,14 +117,9 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
|
||||
jstring host) {
|
||||
const char *hostname;
|
||||
jobjectArray ret = 0;
|
||||
struct hostent res, *hp = 0;
|
||||
// this buffer must be pointer-aligned so is declared
|
||||
// with pointer type
|
||||
char *buf[HENT_BUF_SIZE/(sizeof (char *))];
|
||||
|
||||
/* temporary buffer, on the off chance we need to expand */
|
||||
char *tmp = NULL;
|
||||
int h_error=0;
|
||||
int retLen = 0;
|
||||
int error = 0;
|
||||
struct addrinfo hints, *res, *resNew = NULL;
|
||||
|
||||
if (!initialized) {
|
||||
ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
|
||||
@ -168,6 +140,11 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
|
||||
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
|
||||
CHECK_NULL_RETURN(hostname, NULL);
|
||||
|
||||
/* Try once, with our static buffer. */
|
||||
bzero(&hints, sizeof(hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_family = AF_INET;
|
||||
|
||||
#ifdef __solaris__
|
||||
/*
|
||||
* Workaround for Solaris bug 4160367 - if a hostname contains a
|
||||
@ -181,69 +158,93 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Try once, with our static buffer. */
|
||||
#ifdef __GLIBC__
|
||||
gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &hp, &h_error);
|
||||
#else
|
||||
hp = gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &h_error);
|
||||
#endif
|
||||
error = getaddrinfo(hostname, NULL, &hints, &res);
|
||||
|
||||
/* With the re-entrant system calls, it's possible that the buffer
|
||||
* we pass to it is not large enough to hold an exceptionally
|
||||
* large DNS entry. This is signaled by errno->ERANGE. We try once
|
||||
* more, with a very big size.
|
||||
*/
|
||||
if (hp == NULL && errno == ERANGE) {
|
||||
if ((tmp = (char*)malloc(BIG_HENT_BUF_SIZE))) {
|
||||
#ifdef __GLIBC__
|
||||
gethostbyname_r(hostname, &res, tmp, BIG_HENT_BUF_SIZE,
|
||||
&hp, &h_error);
|
||||
#else
|
||||
hp = gethostbyname_r(hostname, &res, tmp, BIG_HENT_BUF_SIZE,
|
||||
&h_error);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (hp != NULL) {
|
||||
struct in_addr **addrp = (struct in_addr **) hp->h_addr_list;
|
||||
if (error) {
|
||||
/* report error */
|
||||
ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
|
||||
JNU_ReleaseStringPlatformChars(env, host, hostname);
|
||||
return NULL;
|
||||
} else {
|
||||
int i = 0;
|
||||
struct addrinfo *itr, *last = NULL, *iterator = res;
|
||||
|
||||
while (*addrp != (struct in_addr *) 0) {
|
||||
i++;
|
||||
addrp++;
|
||||
while (iterator != NULL) {
|
||||
// remove the duplicate one
|
||||
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;
|
||||
}
|
||||
|
||||
ret = (*env)->NewObjectArray(env, i, ni_iacls, NULL);
|
||||
retLen = i;
|
||||
iterator = resNew;
|
||||
|
||||
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;
|
||||
}
|
||||
addrp = (struct in_addr **) hp->h_addr_list;
|
||||
|
||||
i = 0;
|
||||
while (*addrp) {
|
||||
jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
|
||||
if (IS_NULL(iaObj)) {
|
||||
ret = NULL;
|
||||
goto cleanupAndReturn;
|
||||
}
|
||||
(*env)->SetIntField(env, iaObj, ni_iaaddressID,
|
||||
ntohl((*addrp)->s_addr));
|
||||
(*env)->SetObjectField(env, iaObj, ni_iahostID, host);
|
||||
(*env)->SetObjectArrayElement(env, ret, i, iaObj);
|
||||
addrp++;
|
||||
i++;
|
||||
while (iterator != NULL) {
|
||||
jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
|
||||
if (IS_NULL(iaObj)) {
|
||||
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, host);
|
||||
(*env)->SetObjectArrayElement(env, ret, i++, iaObj);
|
||||
iterator = iterator->ai_next;
|
||||
}
|
||||
} else {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
|
||||
(char *)hostname);
|
||||
ret = NULL;
|
||||
}
|
||||
|
||||
cleanupAndReturn:
|
||||
JNU_ReleaseStringPlatformChars(env, host, hostname);
|
||||
if (tmp != NULL) {
|
||||
free(tmp);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -256,63 +257,39 @@ JNIEXPORT jstring JNICALL
|
||||
Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
|
||||
jbyteArray addrArray) {
|
||||
jstring ret = NULL;
|
||||
jint addr;
|
||||
struct hostent hent, *hp = 0;
|
||||
// this buffer must be pointer-aligned so is declared
|
||||
// with pointer type
|
||||
char *buf[HENT_BUF_SIZE/(sizeof (char *))];
|
||||
int h_error = 0;
|
||||
char *tmp = NULL;
|
||||
|
||||
/*
|
||||
* We are careful here to use the reentrant version of
|
||||
* gethostbyname because at the Java level this routine is not
|
||||
* protected by any synchronization.
|
||||
*
|
||||
* Still keeping the reentrant platform dependent calls temporarily
|
||||
* We should probably conform to one interface later.
|
||||
*
|
||||
*/
|
||||
jbyte caddr[4];
|
||||
char host[NI_MAXHOST+1];
|
||||
int error = 0;
|
||||
int len = 0;
|
||||
jbyte caddr[16];
|
||||
|
||||
struct sockaddr_in him4;
|
||||
struct sockaddr_in6 him6;
|
||||
struct sockaddr *sa;
|
||||
|
||||
jint addr;
|
||||
(*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);
|
||||
addr = htonl(addr);
|
||||
#ifdef __GLIBC__
|
||||
gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET, &hent,
|
||||
(char*)buf, sizeof(buf), &hp, &h_error);
|
||||
#else
|
||||
hp = gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET, &hent,
|
||||
(char*)buf, sizeof(buf), &h_error);
|
||||
#endif
|
||||
/* With the re-entrant system calls, it's possible that the buffer
|
||||
* we pass to it is not large enough to hold an exceptionally
|
||||
* large DNS entry. This is signaled by errno->ERANGE. We try once
|
||||
* more, with a very big size.
|
||||
*/
|
||||
if (hp == NULL && errno == ERANGE) {
|
||||
if ((tmp = (char*)malloc(BIG_HENT_BUF_SIZE))) {
|
||||
#ifdef __GLIBC__
|
||||
gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET,
|
||||
&hent, tmp, BIG_HENT_BUF_SIZE, &hp, &h_error);
|
||||
#else
|
||||
hp = gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET,
|
||||
&hent, tmp, BIG_HENT_BUF_SIZE, &h_error);
|
||||
#endif
|
||||
} else {
|
||||
JNU_ThrowOutOfMemoryError(env, "getHostByAddr");
|
||||
}
|
||||
memset((void *) &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 (hp == NULL) {
|
||||
|
||||
if (ret == NULL) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
|
||||
} else {
|
||||
ret = (*env)->NewStringUTF(env, hp->h_name);
|
||||
}
|
||||
if (tmp) {
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -82,31 +82,29 @@ Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
|
||||
* We use thread-safe system calls.
|
||||
*/
|
||||
#ifdef AF_INET6
|
||||
if (NET_addrtransAvailable()) {
|
||||
struct addrinfo hints, *res;
|
||||
int error;
|
||||
struct addrinfo hints, *res;
|
||||
int error;
|
||||
|
||||
bzero(&hints, sizeof(hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
bzero(&hints, sizeof(hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
|
||||
error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res);
|
||||
error = getaddrinfo(hostname, NULL, &hints, &res);
|
||||
|
||||
if (error == 0) {
|
||||
/* host is known to name service */
|
||||
error = (*getnameinfo_ptr)(res->ai_addr,
|
||||
res->ai_addrlen,
|
||||
hostname,
|
||||
NI_MAXHOST,
|
||||
NULL,
|
||||
0,
|
||||
NI_NAMEREQD);
|
||||
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 */
|
||||
/* if getnameinfo fails hostname is still the value
|
||||
from gethostname */
|
||||
|
||||
(*freeaddrinfo_ptr)(res);
|
||||
}
|
||||
freeaddrinfo(res);
|
||||
}
|
||||
#endif /* AF_INET6 */
|
||||
#endif /* __linux__ */
|
||||
@ -173,193 +171,191 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
|
||||
CHECK_NULL_RETURN(hostname, NULL);
|
||||
|
||||
#ifdef AF_INET6
|
||||
if (NET_addrtransAvailable()) {
|
||||
static jfieldID ia_preferIPv6AddressID;
|
||||
if (ia_preferIPv6AddressID == NULL) {
|
||||
jclass c = (*env)->FindClass(env,"java/net/InetAddress");
|
||||
if (c) {
|
||||
ia_preferIPv6AddressID =
|
||||
(*env)->GetStaticFieldID(env, c, "preferIPv6Address", "Z");
|
||||
}
|
||||
if (ia_preferIPv6AddressID == NULL) {
|
||||
JNU_ReleaseStringPlatformChars(env, host, hostname);
|
||||
return NULL;
|
||||
}
|
||||
static jfieldID ia_preferIPv6AddressID;
|
||||
if (ia_preferIPv6AddressID == NULL) {
|
||||
jclass c = (*env)->FindClass(env,"java/net/InetAddress");
|
||||
if (c) {
|
||||
ia_preferIPv6AddressID =
|
||||
(*env)->GetStaticFieldID(env, c, "preferIPv6Address", "Z");
|
||||
}
|
||||
/* get the address preference */
|
||||
preferIPv6Address
|
||||
= (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID);
|
||||
if (ia_preferIPv6AddressID == NULL) {
|
||||
JNU_ReleaseStringPlatformChars(env, host, hostname);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/* get the address preference */
|
||||
preferIPv6Address
|
||||
= (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID);
|
||||
|
||||
/* Try once, with our static buffer. */
|
||||
bzero(&hints, sizeof(hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
/* Try once, with our static buffer. */
|
||||
bzero(&hints, sizeof(hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
|
||||
#ifdef __solaris__
|
||||
/*
|
||||
* 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",
|
||||
hostname);
|
||||
JNU_ReleaseStringPlatformChars(env, host, hostname);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* 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",
|
||||
hostname);
|
||||
JNU_ReleaseStringPlatformChars(env, host, hostname);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res);
|
||||
error = getaddrinfo(hostname, NULL, &hints, &res);
|
||||
|
||||
if (error) {
|
||||
/* report error */
|
||||
ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
|
||||
JNU_ReleaseStringPlatformChars(env, host, hostname);
|
||||
return NULL;
|
||||
} else {
|
||||
int i = 0;
|
||||
int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
|
||||
struct addrinfo *itr, *last = NULL, *iterator = res;
|
||||
while (iterator != NULL) {
|
||||
int skip = 0;
|
||||
itr = resNew;
|
||||
while (itr != NULL) {
|
||||
if (iterator->ai_family == itr->ai_family &&
|
||||
iterator->ai_addrlen == itr->ai_addrlen) {
|
||||
if (itr->ai_family == AF_INET) { /* AF_INET */
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
int t;
|
||||
struct sockaddr_in6 *addr1, *addr2;
|
||||
addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
|
||||
addr2 = (struct sockaddr_in6 *)itr->ai_addr;
|
||||
if (error) {
|
||||
/* report error */
|
||||
ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
|
||||
JNU_ReleaseStringPlatformChars(env, host, hostname);
|
||||
return NULL;
|
||||
} else {
|
||||
int i = 0;
|
||||
int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
|
||||
struct addrinfo *itr, *last = NULL, *iterator = res;
|
||||
while (iterator != NULL) {
|
||||
int skip = 0;
|
||||
itr = resNew;
|
||||
while (itr != NULL) {
|
||||
if (iterator->ai_family == itr->ai_family &&
|
||||
iterator->ai_addrlen == itr->ai_addrlen) {
|
||||
if (itr->ai_family == AF_INET) { /* AF_INET */
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
int t;
|
||||
struct sockaddr_in6 *addr1, *addr2;
|
||||
addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
|
||||
addr2 = (struct sockaddr_in6 *)itr->ai_addr;
|
||||
|
||||
for (t = 0; t < 16; t++) {
|
||||
if (addr1->sin6_addr.s6_addr[t] !=
|
||||
addr2->sin6_addr.s6_addr[t]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t < 16) {
|
||||
itr = itr->ai_next;
|
||||
continue;
|
||||
} else {
|
||||
skip = 1;
|
||||
for (t = 0; t < 16; t++) {
|
||||
if (addr1->sin6_addr.s6_addr[t] !=
|
||||
addr2->sin6_addr.s6_addr[t]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (iterator->ai_family != AF_INET &&
|
||||
iterator->ai_family != AF_INET6) {
|
||||
/* we can't handle other family types */
|
||||
skip = 1;
|
||||
break;
|
||||
if (t < 16) {
|
||||
itr = itr->ai_next;
|
||||
continue;
|
||||
} else {
|
||||
skip = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
itr = itr->ai_next;
|
||||
} else if (iterator->ai_family != AF_INET &&
|
||||
iterator->ai_family != AF_INET6) {
|
||||
/* we can't handle other family types */
|
||||
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++;
|
||||
if (iterator->ai_family == AF_INET) {
|
||||
inetCount ++;
|
||||
} else if (iterator->ai_family == AF_INET6) {
|
||||
inet6Count ++;
|
||||
}
|
||||
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++;
|
||||
if (iterator->ai_family == AF_INET) {
|
||||
inetCount ++;
|
||||
} else if (iterator->ai_family == AF_INET6) {
|
||||
inet6Count ++;
|
||||
}
|
||||
iterator = iterator->ai_next;
|
||||
}
|
||||
retLen = i;
|
||||
iterator = resNew;
|
||||
iterator = iterator->ai_next;
|
||||
}
|
||||
retLen = i;
|
||||
iterator = resNew;
|
||||
|
||||
ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL);
|
||||
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;
|
||||
}
|
||||
if (IS_NULL(ret)) {
|
||||
/* we may have memory to free at the end of this */
|
||||
goto cleanupAndReturn;
|
||||
}
|
||||
|
||||
if (preferIPv6Address) {
|
||||
/* AF_INET addresses will be offset by inet6Count */
|
||||
inetIndex = inet6Count;
|
||||
inet6Index = 0;
|
||||
} else {
|
||||
/* AF_INET6 addresses will be offset by inetCount */
|
||||
inetIndex = 0;
|
||||
inet6Index = inetCount;
|
||||
}
|
||||
if (preferIPv6Address) {
|
||||
/* AF_INET addresses will be offset by inet6Count */
|
||||
inetIndex = inet6Count;
|
||||
inet6Index = 0;
|
||||
} else {
|
||||
/* AF_INET6 addresses will be offset by inetCount */
|
||||
inetIndex = 0;
|
||||
inet6Index = inetCount;
|
||||
}
|
||||
|
||||
while (iterator != NULL) {
|
||||
if (iterator->ai_family == AF_INET) {
|
||||
while (iterator != NULL) {
|
||||
if (iterator->ai_family == AF_INET) {
|
||||
jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
|
||||
if (IS_NULL(iaObj)) {
|
||||
ret = NULL;
|
||||
goto cleanupAndReturn;
|
||||
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, host);
|
||||
(*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj);
|
||||
inetIndex++;
|
||||
} else if (iterator->ai_family == AF_INET6) {
|
||||
} else if (iterator->ai_family == AF_INET6) {
|
||||
jint scope = 0;
|
||||
jbyteArray ipaddress;
|
||||
|
||||
jobject iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
|
||||
if (IS_NULL(iaObj)) {
|
||||
ret = NULL;
|
||||
goto cleanupAndReturn;
|
||||
ret = NULL;
|
||||
goto cleanupAndReturn;
|
||||
}
|
||||
ipaddress = (*env)->NewByteArray(env, 16);
|
||||
if (IS_NULL(ipaddress)) {
|
||||
ret = NULL;
|
||||
goto cleanupAndReturn;
|
||||
ret = NULL;
|
||||
goto cleanupAndReturn;
|
||||
}
|
||||
(*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
|
||||
(jbyte *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
|
||||
#ifdef __linux__
|
||||
if (!kernelIsV22()) {
|
||||
scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
|
||||
scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
|
||||
}
|
||||
#else
|
||||
scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
|
||||
#endif
|
||||
if (scope != 0) { /* zero is default value, no need to set */
|
||||
(*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
|
||||
(*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
|
||||
(*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
|
||||
(*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
|
||||
}
|
||||
(*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress);
|
||||
(*env)->SetObjectField(env, iaObj, ni_iahostID, host);
|
||||
(*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj);
|
||||
inet6Index++;
|
||||
}
|
||||
iterator = iterator->ai_next;
|
||||
}
|
||||
iterator = iterator->ai_next;
|
||||
}
|
||||
}
|
||||
|
||||
cleanupAndReturn:
|
||||
cleanupAndReturn:
|
||||
{
|
||||
struct addrinfo *iterator, *tmp;
|
||||
struct addrinfo *iterator, *tmp;
|
||||
iterator = resNew;
|
||||
while (iterator != NULL) {
|
||||
tmp = iterator;
|
||||
@ -369,8 +365,7 @@ cleanupAndReturn:
|
||||
JNU_ReleaseStringPlatformChars(env, host, hostname);
|
||||
}
|
||||
|
||||
if (NET_addrtransAvailable())
|
||||
(*freeaddrinfo_ptr)(res);
|
||||
freeaddrinfo(res);
|
||||
#endif /* AF_INET6 */
|
||||
|
||||
return ret;
|
||||
@ -393,44 +388,42 @@ Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
|
||||
int len = 0;
|
||||
jbyte caddr[16];
|
||||
|
||||
if (NET_addrtransAvailable()) {
|
||||
struct sockaddr_in him4;
|
||||
struct sockaddr_in6 him6;
|
||||
struct sockaddr *sa;
|
||||
struct sockaddr_in him4;
|
||||
struct sockaddr_in6 him6;
|
||||
struct sockaddr *sa;
|
||||
|
||||
/*
|
||||
* For IPv4 addresses construct a sockaddr_in structure.
|
||||
*/
|
||||
if ((*env)->GetArrayLength(env, addrArray) == 4) {
|
||||
jint addr;
|
||||
(*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((void *) &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);
|
||||
} else {
|
||||
/*
|
||||
* For IPv4 addresses construct a sockaddr_in structure.
|
||||
* For IPv6 address construct a sockaddr_in6 structure.
|
||||
*/
|
||||
if ((*env)->GetArrayLength(env, addrArray) == 4) {
|
||||
jint addr;
|
||||
(*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((void *) &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);
|
||||
} else {
|
||||
/*
|
||||
* For IPv6 address construct a sockaddr_in6 structure.
|
||||
*/
|
||||
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
|
||||
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 ;
|
||||
len = sizeof(him6) ;
|
||||
}
|
||||
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
|
||||
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 ;
|
||||
len = sizeof(him6) ;
|
||||
}
|
||||
|
||||
error = (*getnameinfo_ptr)(sa, len, host, NI_MAXHOST, NULL, 0,
|
||||
NI_NAMEREQD);
|
||||
error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
|
||||
NI_NAMEREQD);
|
||||
|
||||
if (!error) {
|
||||
ret = (*env)->NewStringUTF(env, host);
|
||||
}
|
||||
if (!error) {
|
||||
ret = (*env)->NewStringUTF(env, host);
|
||||
}
|
||||
#endif /* AF_INET6 */
|
||||
|
||||
|
||||
@ -377,37 +377,12 @@ jint IPv6_supported()
|
||||
* we should also check if the APIs are available.
|
||||
*/
|
||||
ipv6_fn = JVM_FindLibraryEntry(RTLD_DEFAULT, "inet_pton");
|
||||
if (ipv6_fn == NULL ) {
|
||||
close(fd);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* We've got the library, let's get the pointers to some
|
||||
* IPV6 specific functions. We have to do that because, at least
|
||||
* on Solaris we may build on a system without IPV6 networking
|
||||
* libraries, therefore we can't have a hard link to these
|
||||
* functions.
|
||||
*/
|
||||
getaddrinfo_ptr = (getaddrinfo_f)
|
||||
JVM_FindLibraryEntry(RTLD_DEFAULT, "getaddrinfo");
|
||||
|
||||
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) {
|
||||
/* We need all 3 of them */
|
||||
getaddrinfo_ptr = NULL;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return JNI_TRUE;
|
||||
if (ipv6_fn == NULL ) {
|
||||
return JNI_FALSE;
|
||||
} else {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
#endif /* AF_INET6 */
|
||||
}
|
||||
|
||||
@ -920,10 +895,6 @@ NET_IsEqual(jbyte* caddr1, jbyte* caddr2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
jboolean NET_addrtransAvailable() {
|
||||
return (jboolean)(getaddrinfo_ptr != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the Java level socket option to the platform specific
|
||||
* level and option name.
|
||||
|
||||
@ -102,10 +102,6 @@ void ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
|
||||
const char* hostname,
|
||||
int gai_error);
|
||||
|
||||
/* do we have address translation support */
|
||||
|
||||
extern jboolean NET_addrtransAvailable();
|
||||
|
||||
#define NET_WAIT_READ 0x01
|
||||
#define NET_WAIT_WRITE 0x02
|
||||
#define NET_WAIT_CONNECT 0x04
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user