Merge "Handle recvfrom() returning 0."
diff --git a/luni/src/test/java/libcore/java/net/URLTest.java b/luni/src/test/java/libcore/java/net/URLTest.java
index 2717d14..789e3e9 100644
--- a/luni/src/test/java/libcore/java/net/URLTest.java
+++ b/luni/src/test/java/libcore/java/net/URLTest.java
@@ -750,4 +750,11 @@
BlockGuard.setThreadPolicy(oldPolicy);
}
}
+
+ // http://27444667
+ public void testEmptyQueryAndAnchor() throws Exception {
+ assertEquals("/some/path", new URL("http://foobar.com/some/path?").getFile());
+ assertEquals("/some/path", new URL("http://foobar.com/some/path#").getFile());
+ assertEquals("/some/path", new URL("http://foobar.com/some/path?#").getFile());
+ }
}
diff --git a/ojluni/src/main/java/java/net/URL.java b/ojluni/src/main/java/java/net/URL.java
index b585e2b..70825a0 100755
--- a/ojluni/src/main/java/java/net/URL.java
+++ b/ojluni/src/main/java/java/net/URL.java
@@ -708,7 +708,7 @@
this.protocol = protocol;
this.host = host;
this.port = port;
- this.file = query == null ? path : path + "?" + query;
+ this.file = (query == null || query.isEmpty()) ? path : path + "?" + query;
this.userInfo = userInfo;
this.path = path;
this.ref = ref;
diff --git a/ojluni/src/main/java/java/net/URLStreamHandler.java b/ojluni/src/main/java/java/net/URLStreamHandler.java
index e64b9b8..e177363 100755
--- a/ojluni/src/main/java/java/net/URLStreamHandler.java
+++ b/ojluni/src/main/java/java/net/URLStreamHandler.java
@@ -337,6 +337,10 @@
// Remove trailing .
if (path.endsWith("/."))
path = path.substring(0, path.length() -1);
+
+ // Remove trailing ?
+ if (path.endsWith("?"))
+ path = path.substring(0, path.length() -1);
}
setURL(u, protocol, host, port, authority, userInfo, path, query, ref);
diff --git a/ojluni/src/main/native/Inet4AddressImpl.c b/ojluni/src/main/native/Inet4AddressImpl.c
index c424337..2856576 100755
--- a/ojluni/src/main/native/Inet4AddressImpl.c
+++ b/ojluni/src/main/native/Inet4AddressImpl.c
@@ -99,6 +99,7 @@
if (netif != NULL) {
if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
NET_ThrowNew(env, errno, "Can't bind socket");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -137,6 +138,7 @@
*/
#endif /*__linux__ */
NET_ThrowNew(env, errno, "Can't send ICMP packet");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -158,11 +160,13 @@
if (icmplen >= 8 && icmp->icmp_type == ICMP_ECHOREPLY
&& (ntohs(icmp->icmp_id) == pid)) {
if ((him->sin_addr.s_addr == sa_recv.sin_addr.s_addr)) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
}
if (him->sin_addr.s_addr == 0) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
}
@@ -172,6 +176,7 @@
} while (tmout2 > 0);
timeout -= 1000;
} while (timeout >0);
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -240,6 +245,7 @@
/*
* It didn't fail, so we can use ICMP_ECHO requests.
*/
+ tagSocket(env, fd);
return ping4(env, fd, &him, timeout, netif, ttl);
}
@@ -255,6 +261,8 @@
NET_ThrowNew(env, errno, "Can't create socket");
return JNI_FALSE;
}
+ tagSocket(env, fd);
+
if (ttl > 0) {
setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
}
@@ -265,6 +273,7 @@
if (netif != NULL) {
if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
NET_ThrowNew(env, errno, "Can't bind socket");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -284,6 +293,7 @@
* we were able to reach the host!
*/
if (connect_rv == 0 || errno == ECONNREFUSED) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
} else {
@@ -302,6 +312,7 @@
* When that happens, don't throw an exception, just return false.
*/
#endif /* __linux__ */
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -309,6 +320,7 @@
if (errno != EINPROGRESS) {
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
"connect failed");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -322,10 +334,12 @@
connect_rv = errno;
}
if (connect_rv == 0 || connect_rv == ECONNREFUSED) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
}
}
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
diff --git a/ojluni/src/main/native/Inet6AddressImpl.c b/ojluni/src/main/native/Inet6AddressImpl.c
index 27f03ce..ec766c9 100755
--- a/ojluni/src/main/native/Inet6AddressImpl.c
+++ b/ojluni/src/main/native/Inet6AddressImpl.c
@@ -180,6 +180,7 @@
if (netif != NULL) {
if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
NET_ThrowNew(env, errno, "Can't bind socket");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -209,6 +210,7 @@
*/
#endif /*__linux__ */
NET_ThrowNew(env, errno, "Can't send ICMP packet");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -230,10 +232,12 @@
if (n >= 8 && icmp6->icmp6_type == ICMP6_ECHO_REPLY &&
(ntohs(icmp6->icmp6_id) == pid)) {
if (NET_IsEqual(caddr, recv_caddr)) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
}
if (NET_IsZeroAddr(caddr)) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
}
@@ -242,6 +246,7 @@
} while (tmout2 > 0);
timeout -= 1000;
} while (timeout > 0);
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -322,6 +327,7 @@
fd = JVM_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
if (fd != -1) { /* Good to go, let's do a ping */
+ tagSocket(env, fd);
return ping6(env, fd, &him6, timeout, netif, ttl);
}
@@ -335,6 +341,8 @@
NET_ThrowNew(env, errno, "Can't create socket");
return JNI_FALSE;
}
+ tagSocket(env, fd);
+
if (ttl > 0) {
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
}
@@ -345,6 +353,7 @@
if (netif != NULL) {
if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
NET_ThrowNew(env, errno, "Can't bind socket");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -360,6 +369,7 @@
* we were able to reach the host!
*/
if (connect_rv == 0 || errno == ECONNREFUSED) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
} else {
@@ -378,6 +388,7 @@
* When that happens, don't throw an exception, just return false.
*/
#endif /* __linux__ */
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -385,6 +396,7 @@
if (errno != EINPROGRESS) {
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
"connect failed");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -399,10 +411,12 @@
connect_rv = errno;
}
if (connect_rv == 0 || ECONNREFUSED) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
}
}
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
diff --git a/ojluni/src/main/native/Net.c b/ojluni/src/main/native/Net.c
index 3bdbf4d..e7cd5d7 100644
--- a/ojluni/src/main/native/Net.c
+++ b/ojluni/src/main/native/Net.c
@@ -167,6 +167,7 @@
#endif
fd = socket(domain, type, 0);
+ tagSocket(env, fd);
if (fd < 0) {
return handleSocketError(env, errno);
}
@@ -180,6 +181,7 @@
JNU_ThrowByNameWithLastError(env,
JNU_JAVANETPKG "SocketException",
"sun.nio.ch.Net.setIntOption");
+ untagSocket(env, fd);
close(fd);
return -1;
}
@@ -193,6 +195,7 @@
JNU_ThrowByNameWithLastError(env,
JNU_JAVANETPKG "SocketException",
"sun.nio.ch.Net.setIntOption");
+ untagSocket(env, fd);
close(fd);
return -1;
}
@@ -206,6 +209,7 @@
JNU_ThrowByNameWithLastError(env,
JNU_JAVANETPKG "SocketException",
"sun.nio.ch.Net.setIntOption");
+ untagSocket(env, fd);
close(fd);
return -1;
}
diff --git a/ojluni/src/main/native/NetworkInterface.c b/ojluni/src/main/native/NetworkInterface.c
index ff80041..94cdd03 100755
--- a/ojluni/src/main/native/NetworkInterface.c
+++ b/ojluni/src/main/native/NetworkInterface.c
@@ -452,6 +452,7 @@
(*env)->ReleaseStringUTFChars(env, name, name_utf);
+ untagSocket(env, sock);
close(sock);
return ret;
}
@@ -475,6 +476,7 @@
ret = getFlags(sock, name_utf, &flags);
+ untagSocket(env, sock);
close(sock);
(*env)->ReleaseStringUTFChars(env, name, name_utf);
@@ -705,6 +707,7 @@
}
freeifaddrs(origifa);
+ untagSocket(env, sock);
close(sock);
return ifs;
@@ -985,6 +988,7 @@
return -1;
}
+ tagSocket(env, sock);
return sock;
}
@@ -1015,6 +1019,7 @@
/* Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or IPv6 socket regardless of type
of address of an interface */
+ tagSocket(env, sock);
return sock;
}
diff --git a/ojluni/src/main/native/PlainDatagramSocketImpl.c b/ojluni/src/main/native/PlainDatagramSocketImpl.c
index f4857df..1b1e3f6 100755
--- a/ojluni/src/main/native/PlainDatagramSocketImpl.c
+++ b/ojluni/src/main/native/PlainDatagramSocketImpl.c
@@ -987,6 +987,7 @@
"Error creating socket");
return;
}
+ tagSocket(env, fd);
#ifdef AF_INET6
/* Disable IPV6_V6ONLY to ensure dual-socket support */
@@ -995,6 +996,7 @@
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
sizeof(int)) < 0) {
NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
+ untagSocket(env, fd);
close(fd);
return;
}
@@ -1059,6 +1061,7 @@
return;
}
(*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
+ untagSocket(env, fd);
NET_SocketClose(fd);
}
diff --git a/ojluni/src/main/native/PlainSocketImpl.c b/ojluni/src/main/native/PlainSocketImpl.c
index 5010851..db25104 100755
--- a/ojluni/src/main/native/PlainSocketImpl.c
+++ b/ojluni/src/main/native/PlainSocketImpl.c
@@ -180,6 +180,7 @@
NET_ThrowNew(env, errno, "can't create socket");
return;
}
+ tagSocket(env, fd);
#ifdef AF_INET6
/* Disable IPV6_V6ONLY to ensure dual-socket support */
@@ -188,6 +189,7 @@
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
sizeof(int)) < 0) {
NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
+ untagSocket(env, fd);
close(fd);
return;
}
@@ -205,6 +207,7 @@
if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
sizeof(arg)) < 0) {
NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR");
+ untagSocket(env, fd);
close(fd);
return;
}
@@ -746,6 +749,7 @@
socketAddressObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
if (socketAddressObj == NULL) {
/* should be pending exception */
+ untagSocket(env, fd);
close(newfd);
return;
}
@@ -815,6 +819,7 @@
}
if (fd != -1) {
(*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
+ untagSocket(env, fd);
NET_SocketClose(fd);
}
}
diff --git a/ojluni/src/main/native/net_util_md.c b/ojluni/src/main/native/net_util_md.c
index 27a45ad..c41d8bc 100755
--- a/ojluni/src/main/native/net_util_md.c
+++ b/ojluni/src/main/native/net_util_md.c
@@ -412,6 +412,7 @@
/**
* SIOCGLIFNUM failed - assume IPv6 not configured
*/
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
diff --git a/ojluni/src/main/native/net_util_md.h b/ojluni/src/main/native/net_util_md.h
index cc0c033..46fa8dd 100755
--- a/ojluni/src/main/native/net_util_md.h
+++ b/ojluni/src/main/native/net_util_md.h
@@ -59,6 +59,9 @@
extern int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout);
#endif
+extern int tagSocket(JNIEnv* env, int fd);
+extern void untagSocket(JNIEnv* env, int fd);
+
#else
#define NET_Timeout JVM_Timeout
@@ -75,6 +78,9 @@
#define NET_Select select
#define NET_Poll poll
+#define tagSocket(env,fd) (void)0
+#define untagSocket(env,fd) (void)0
+
#endif
diff --git a/ojluni/src/main/native/openjdksub.mk b/ojluni/src/main/native/openjdksub.mk
index 6ec6be1..1f88335 100644
--- a/ojluni/src/main/native/openjdksub.mk
+++ b/ojluni/src/main/native/openjdksub.mk
@@ -66,6 +66,7 @@
Bits.c \
Character.cpp \
Register.cpp \
+ socket_tagger_util.cpp \
LOCAL_C_INCLUDES += \
libcore/$(srcdir) \
diff --git a/ojluni/src/main/native/socket_tagger_util.cpp b/ojluni/src/main/native/socket_tagger_util.cpp
new file mode 100644
index 0000000..b03d0aa
--- /dev/null
+++ b/ojluni/src/main/native/socket_tagger_util.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Google designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Google in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "JNIHelp.h"
+#include "JniConstants.h"
+
+extern "C" {
+
+int tagSocket(JNIEnv* env, int fd) {
+ if (env->ExceptionOccurred()) { return fd; }
+ jmethodID get = env->GetStaticMethodID(JniConstants::socketTaggerClass,
+ "get", "()Ldalvik/system/SocketTagger;");
+ jobject socketTagger =
+ env->CallStaticObjectMethod(JniConstants::socketTaggerClass, get);
+ jmethodID tag = env->GetMethodID(JniConstants::socketTaggerClass,
+ "tag", "(Ljava/io/FileDescriptor;)V");
+
+ jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
+ env->CallVoidMethod(socketTagger, tag, fileDescriptor);
+ return fd;
+}
+
+void untagSocket(JNIEnv* env, int fd) {
+ if (env->ExceptionOccurred()) { return; }
+ jmethodID get = env->GetStaticMethodID(JniConstants::socketTaggerClass,
+ "get", "()Ldalvik/system/SocketTagger;");
+ jobject socketTagger =
+ env->CallStaticObjectMethod(JniConstants::socketTaggerClass, get);
+ jmethodID untag = env->GetMethodID(JniConstants::socketTaggerClass,
+ "untag", "(Ljava/io/FileDescriptor;)V");
+
+ jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
+ env->CallVoidMethod(socketTagger, untag, fileDescriptor);
+}
+
+}