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);
+}
+
+}