mirror of
https://github.com/yann64/haikuports.git
synced 2026-04-16 16:50:06 +02:00
365 lines
13 KiB
Plaintext
365 lines
13 KiB
Plaintext
From 21be8c5d2379b6dbf75a09a751bc4401dbec205c Mon Sep 17 00:00:00 2001
|
|
From: Sergei Reznikov <diver@gelios.net>
|
|
Date: Wed, 7 Oct 2015 15:22:29 +0300
|
|
Subject: Inet4AddressImpl: replace gethostbyname_r with getaddrinfo
|
|
|
|
Backport OpenJDK 8 implementation, not completely working yet, e.g.
|
|
muCommander can't connect to smb shares for some reason.
|
|
|
|
diff --git a/src/solaris/native/java/net/Inet4AddressImpl.c b/src/solaris/native/java/net/Inet4AddressImpl.c
|
|
index 2c2a6b1..bfd2755 100644
|
|
--- a/src/solaris/native/java/net/Inet4AddressImpl.c
|
|
+++ b/src/solaris/native/java/net/Inet4AddressImpl.c
|
|
@@ -351,60 +351,36 @@ Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
|
|
*/
|
|
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 {
|
|
-#if defined(__linux__) || (__HAIKU__)
|
|
- /* 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;
|
|
-
|
|
- // ensure null-terminated
|
|
- hostname[MAXHOSTNAMELEN] = '\0';
|
|
-
|
|
-#ifdef HAS_GLIBC_GETHOSTBY_R
|
|
- 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 HAS_GLIBC_GETHOSTBY_R
|
|
- 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);
|
|
- }
|
|
+ struct addrinfo hints, *res;
|
|
+ int error;
|
|
+
|
|
+ hostname[NI_MAXHOST] = '\0';
|
|
+ memset(&hints, 0, sizeof(hints));
|
|
+ hints.ai_flags = AI_CANONNAME;
|
|
+ hints.ai_family = AF_INET;
|
|
+
|
|
+ error = getaddrinfo(hostname, NULL, &hints, &res);
|
|
+
|
|
+ if (error == 0) {/* host is known to name service */
|
|
+ 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);
|
|
@@ -426,14 +402,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 (!initializeInetClasses(env))
|
|
return NULL;
|
|
@@ -445,6 +416,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. */
|
|
+ memset(&hints, 0, sizeof(hints));
|
|
+ hints.ai_flags = AI_CANONNAME;
|
|
+ hints.ai_family = AF_INET;
|
|
+
|
|
#ifdef __solaris__
|
|
/*
|
|
* Workaround for Solaris bug 4160367 - if a hostname contains a
|
|
@@ -458,71 +434,96 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
|
|
}
|
|
#endif
|
|
|
|
- /* Try once, with our static buffer. */
|
|
-#ifdef HAS_GLIBC_GETHOSTBY_R
|
|
- 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 HAS_GLIBC_GETHOSTBY_R
|
|
- 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, "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;
|
|
}
|
|
|
|
- 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;
|
|
- }
|
|
- setInetAddress_addr(env, iaObj, ntohl((*addrp)->s_addr));
|
|
- setInetAddress_hostName(env, iaObj, 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;
|
|
+ }
|
|
+ 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 {
|
|
- 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;
|
|
}
|
|
|
|
+
|
|
/*
|
|
* Class: java_net_Inet4AddressImpl
|
|
* Method: getHostByAddr
|
|
@@ -532,66 +533,40 @@ 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.
|
|
- *
|
|
- */
|
|
+ char host[NI_MAXHOST+1];
|
|
+ int error = 0;
|
|
+ int len = 0;
|
|
jbyte caddr[4];
|
|
+
|
|
+ struct sockaddr_in him4;
|
|
+ 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 HAS_GLIBC_GETHOSTBY_R
|
|
- 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 HAS_GLIBC_GETHOSTBY_R
|
|
- 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;
|
|
}
|
|
-
|
|
#endif /* _ALLBSD_SOURCE */
|
|
|
|
#define SET_NONBLOCKING(fd) { \
|
|
--
|
|
2.2.2
|
|
|