Merge "Add a warning about relative paths to ZipEntry#getName."
diff --git a/expectations/brokentests.txt b/expectations/brokentests.txt
index 2ff723f..0a047a2 100644
--- a/expectations/brokentests.txt
+++ b/expectations/brokentests.txt
@@ -67,7 +67,6 @@
   result: EXEC_FAILED,
   names: [
     "org.apache.harmony.tests.java.net.Inet6AddressTest#test_getByNameLjava_lang_String",
-    "org.apache.harmony.tests.java.net.InetAddressTest#test_equalsLjava_lang_Object",
     "org.apache.harmony.tests.java.net.InetAddressTest#test_getByNameLjava_lang_String",
     "org.apache.harmony.tests.java.net.InetAddressTest#test_isReachableLjava_net_NetworkInterfaceII_loopbackInterface"
   ]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
index 42f88c1..e5742d7 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
@@ -47,7 +47,7 @@
     }
 
     public void test_equalsLjava_lang_Object() throws Exception {
-        InetAddress ia1 = InetAddress.getByName("localhost");
+        InetAddress ia1 = InetAddress.getByName("ip6-localhost");
         InetAddress ia2 = InetAddress.getByName("::1");
         assertEquals(ia2, ia1);
     }
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/org/apache/harmony/kernel/dalvik/ThreadsTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/org/apache/harmony/kernel/dalvik/ThreadsTest.java
index 19c6229..c971e99 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/org/apache/harmony/kernel/dalvik/ThreadsTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/org/apache/harmony/kernel/dalvik/ThreadsTest.java
@@ -234,10 +234,10 @@
              * Allow a bit more slop for the maximum on "expected
              * instantaneous" results.
              */
-            long minimum = (long) ((double) expectedMillis * 0.90);
+            long minimum = (long) ((double) expectedMillis * 0.80);
             long maximum =
-                Math.max((long) ((double) expectedMillis * 1.10), 10);
-            long waitMillis = Math.max(expectedMillis * 10, 10);
+                Math.max((long) ((double) expectedMillis * 1.20), 10);
+            long waitMillis = Math.max(expectedMillis * 10, 30);
             long duration = getDurationMillis(waitMillis);
 
             if (duration < minimum) {
diff --git a/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index b054fb3..b885ed2 100644
--- a/libart/src/main/java/dalvik/system/VMRuntime.java
+++ b/libart/src/main/java/dalvik/system/VMRuntime.java
@@ -276,6 +276,12 @@
     public native void clearGrowthLimit();
 
     /**
+     * Make the current growth limit the new non growth limit capacity by releasing pages which
+     * are after the growth limit but before the non growth limit capacity.
+     */
+    public native void clampGrowthLimit();
+
+    /**
      * Returns true if either a Java debugger or native debugger is active.
      */
     public native boolean isDebuggerActive();
diff --git a/luni/src/main/java/java/io/FileDescriptor.java b/luni/src/main/java/java/io/FileDescriptor.java
index eba0e4d..be94c52 100644
--- a/luni/src/main/java/java/io/FileDescriptor.java
+++ b/luni/src/main/java/java/io/FileDescriptor.java
@@ -108,7 +108,7 @@
     /**
      * @hide internal use only
      */
-    public boolean isSocket() {
+    public final boolean isSocket$() {
         return isSocket(descriptor);
     }
 
diff --git a/luni/src/main/java/java/net/Inet6Address.java b/luni/src/main/java/java/net/Inet6Address.java
index 8ab0f8d..347f43a 100644
--- a/luni/src/main/java/java/net/Inet6Address.java
+++ b/luni/src/main/java/java/net/Inet6Address.java
@@ -43,7 +43,7 @@
      */
     public static final InetAddress LOOPBACK =
             new Inet6Address(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
-                    "localhost", 0);
+                    "ip6-localhost", 0);
 
     private boolean scope_id_set;
     private int scope_id;
diff --git a/luni/src/main/java/java/net/InetAddress.java b/luni/src/main/java/java/net/InetAddress.java
index 6a02e0d..581e1bd 100644
--- a/luni/src/main/java/java/net/InetAddress.java
+++ b/luni/src/main/java/java/net/InetAddress.java
@@ -202,10 +202,10 @@
     /**
      * Gets all IP addresses associated with the given {@code host} identified
      * by name or literal IP address. The IP address is resolved by the
-     * configured name service. If the host name is empty or {@code null} an
-     * {@code UnknownHostException} is thrown. If the host name is a literal IP
-     * address string an array with the corresponding single {@code InetAddress}
-     * is returned.
+     * configured name service. If the host name is empty or {@code null} the
+     * IP addresses of the loopback interfaces are returned. If the host name
+     * is a literal IP address string an array with the corresponding single
+     * {@code InetAddress} is returned.
      *
      * @param host the hostname or literal IP string to be resolved.
      * @return the array of addresses associated with the specified host.
diff --git a/luni/src/main/java/java/nio/channels/Selector.java b/luni/src/main/java/java/nio/channels/Selector.java
index 6d9b063..baa6a7f 100644
--- a/luni/src/main/java/java/nio/channels/Selector.java
+++ b/luni/src/main/java/java/nio/channels/Selector.java
@@ -78,8 +78,11 @@
     public abstract boolean isOpen();
 
     /**
-     * Gets the set of registered keys. The set is immutable and is not thread-
-     * safe.
+     * Gets the set of registered keys.
+     *
+     * <p>The returned set cannot be changed directly but can be modified
+     * indirectly by operations on the Selector. It should therefore not be
+     * treated as thread-safe.
      *
      * @return the set of registered keys.
      */
@@ -127,9 +130,11 @@
     public abstract int select(long timeout) throws IOException;
 
     /**
-     * Gets the selection keys whose channels are ready for operation. The set
-     * is not thread-safe and no keys may be added to it. Removing keys is
-     * allowed.
+     * Gets the selection keys whose channels are ready for operation.
+     *
+     * <p>Keys cannot be added to the set directly. Keys can be removed.
+     * The set can be modified indirectly by operations on the Selector. It
+     * should therefore not be treated as thread-safe.
      *
      * @return the selection keys whose channels are ready for operation.
      * @throws ClosedSelectorException
diff --git a/luni/src/main/java/libcore/io/BlockGuardOs.java b/luni/src/main/java/libcore/io/BlockGuardOs.java
index b3dc74b..532493a 100644
--- a/luni/src/main/java/libcore/io/BlockGuardOs.java
+++ b/luni/src/main/java/libcore/io/BlockGuardOs.java
@@ -83,7 +83,7 @@
             // The usual case is that this _isn't_ a socket, so the getsockopt(2) call in
             // isLingerSocket will throw, and that's really expensive. Try to avoid asking
             // if we don't care.
-            if (fd.isSocket()) {
+            if (fd.isSocket$()) {
                 if (isLingerSocket(fd)) {
                     // If the fd is a socket with SO_LINGER set, we might block indefinitely.
                     // We allow non-linger sockets so that apps can close their network
diff --git a/luni/src/main/native/java_io_FileDescriptor.cpp b/luni/src/main/native/java_io_FileDescriptor.cpp
index fe7e07e..2a7820f 100644
--- a/luni/src/main/native/java_io_FileDescriptor.cpp
+++ b/luni/src/main/native/java_io_FileDescriptor.cpp
@@ -22,9 +22,11 @@
 #include <sys/types.h>
 
 static jboolean FileDescriptor_isSocket(JNIEnv*, jclass, jint fd) {
-  int error;
-  socklen_t error_length = sizeof(error);
-  return TEMP_FAILURE_RETRY(getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &error_length));
+  // If getsockopt succeeds, we know we're dealing with a socket.
+  // This is the cheapest way we know of to test whether an fd is a socket.
+  int option;
+  socklen_t option_length = sizeof(option);
+  return TEMP_FAILURE_RETRY(getsockopt(fd, SOL_SOCKET, SO_DEBUG, &option, &option_length)) == 0;
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/luni/src/main/native/java_util_jar_StrictJarFile.cpp b/luni/src/main/native/java_util_jar_StrictJarFile.cpp
index f0cdbed..82547bd 100644
--- a/luni/src/main/native/java_util_jar_StrictJarFile.cpp
+++ b/luni/src/main/native/java_util_jar_StrictJarFile.cpp
@@ -28,16 +28,15 @@
 #include "ziparchive/zip_archive.h"
 #include "cutils/log.h"
 
+// The method ID for ZipEntry.<init>(String,String,JJJIII[BJJ)
+static jmethodID zipEntryCtor;
+
 static void throwIoException(JNIEnv* env, const int32_t errorCode) {
   jniThrowException(env, "java/io/IOException", ErrorCodeString(errorCode));
 }
 
 static jobject newZipEntry(JNIEnv* env, const ZipEntry& entry, jstring entryName) {
-  ScopedLocalRef<jclass> zipEntryClass(env, env->FindClass("java/util/zip/ZipEntry"));
-  const jmethodID zipEntryCtor = env->GetMethodID(zipEntryClass.get(), "<init>",
-                                   "(Ljava/lang/String;Ljava/lang/String;JJJIII[BJJ)V");
-
-  return env->NewObject(zipEntryClass.get(),
+  return env->NewObject(JniConstants::zipEntryClass,
                         zipEntryCtor,
                         entryName,
                         NULL,  // comment
@@ -164,4 +163,7 @@
 void register_java_util_jar_StrictJarFile(JNIEnv* env) {
   jniRegisterNativeMethods(env, "java/util/jar/StrictJarFile", gMethods, NELEM(gMethods));
 
+  zipEntryCtor = env->GetMethodID(JniConstants::zipEntryClass, "<init>",
+      "(Ljava/lang/String;Ljava/lang/String;JJJIII[BJJ)V");
+  LOG_ALWAYS_FATAL_IF(zipEntryCtor == NULL, "Unable to find ZipEntry.<init>");
 }
diff --git a/luni/src/test/java/libcore/java/io/FileDescriptorTest.java b/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
index 4315b81..e2780c9 100644
--- a/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
+++ b/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
@@ -17,14 +17,27 @@
 package libcore.java.io;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.RandomAccessFile;
+import java.net.ServerSocket;
 import junit.framework.TestCase;
 
 public class FileDescriptorTest extends TestCase {
-    public void testReadOnlyFileDescriptorSync() throws Exception {
-        File f= File.createTempFile("FileDescriptorTest", "tmp");
-        new RandomAccessFile(f, "r").getFD().sync();
-    }
+  public void testReadOnlyFileDescriptorSync() throws Exception {
+    File f= File.createTempFile("FileDescriptorTest", "tmp");
+    new RandomAccessFile(f, "r").getFD().sync();
+  }
+
+  public void test_isSocket$() throws Exception {
+    File f = new File("/dev/null");
+    FileInputStream fis = new FileInputStream(f);
+    assertFalse(fis.getFD().isSocket$());
+    fis.close();
+
+    ServerSocket s = new ServerSocket();
+    assertTrue(s.getImpl$().getFD$().isSocket$());
+    s.close();
+  }
 }
diff --git a/luni/src/test/java/libcore/java/net/InetAddressTest.java b/luni/src/test/java/libcore/java/net/InetAddressTest.java
index 7a96b0b..8bdcf64 100644
--- a/luni/src/test/java/libcore/java/net/InetAddressTest.java
+++ b/luni/src/test/java/libcore/java/net/InetAddressTest.java
@@ -19,13 +19,16 @@
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
-import java.net.InetSocketAddress;
 import java.net.NetworkInterface;
 import java.net.UnknownHostException;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
 import libcore.util.SerializationTester;
 
 public class InetAddressTest extends junit.framework.TestCase {
+    private static final byte[] LOOPBACK4_BYTES = new byte[] { 127, 0, 0, 1 };
     private static final byte[] LOOPBACK6_BYTES = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
 
     private static final String[] INVALID_IPv4_NUMERIC_ADDRESSES = new String[] {
@@ -73,7 +76,7 @@
     }
 
     private static Inet6Address localhost6() throws Exception {
-        return (Inet6Address) InetAddress.getByAddress("localhost", LOOPBACK6_BYTES);
+        return (Inet6Address) InetAddress.getByAddress("ip6-localhost", LOOPBACK6_BYTES);
     }
 
     public void test_parseNumericAddress() throws Exception {
@@ -313,15 +316,83 @@
         }
     }
 
-    public void test_getHostString() throws Exception {
-        InetAddress inetAddress = InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 });
-        assertEquals("127.0.0.1", inetAddress.getHostString());
-        assertEquals("localhost", inetAddress.getHostName());
-        assertEquals("localhost", inetAddress.getHostString());
+    public void test_getHostNameCaches() throws Exception {
+        InetAddress inetAddress = InetAddress.getByAddress(LOOPBACK6_BYTES);
+        assertEquals("::1", inetAddress.getHostString());
+        assertEquals("ip6-localhost", inetAddress.getHostName());
+        // getHostString() should now be different.
+        assertEquals("ip6-localhost", inetAddress.getHostString());
+    }
 
-        inetAddress = InetAddress.getByName("127.0.0.1");
-        assertEquals("127.0.0.1", inetAddress.getHostString());
-        assertEquals("localhost", inetAddress.getHostName());
-        assertEquals("localhost", inetAddress.getHostString());
+    public void test_getByAddress_loopbackIpv4() throws Exception {
+        InetAddress inetAddress = InetAddress.getByAddress(LOOPBACK4_BYTES);
+        assertEquals(LOOPBACK4_BYTES, "localhost", inetAddress);
+        assertTrue(inetAddress.isLoopbackAddress());
+    }
+
+    public void test_getByAddress_loopbackIpv6() throws Exception {
+        InetAddress inetAddress = InetAddress.getByAddress(LOOPBACK6_BYTES);
+        assertEquals(LOOPBACK6_BYTES, "ip6-localhost", inetAddress);
+        assertTrue(inetAddress.isLoopbackAddress());
+    }
+
+    public void test_getByName_loopbackIpv4() throws Exception {
+        InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
+        assertEquals(LOOPBACK4_BYTES, "localhost", inetAddress);
+        assertTrue(inetAddress.isLoopbackAddress());
+    }
+
+    public void test_getByName_loopbackIpv6() throws Exception {
+        InetAddress inetAddress = InetAddress.getByName("::1");
+        assertEquals(LOOPBACK6_BYTES, "ip6-localhost", inetAddress);
+        assertTrue(inetAddress.isLoopbackAddress());
+    }
+
+    public void test_getAllByName_localhost() throws Exception {
+        InetAddress[] inetAddresses = InetAddress.getAllByName("localhost");
+        assertEquals(1, inetAddresses.length);
+        InetAddress inetAddress = inetAddresses[0];
+        assertEquals(LOOPBACK4_BYTES, "localhost", inetAddress);
+        assertTrue(inetAddress.isLoopbackAddress());
+    }
+
+    public void test_getAllByName_ip6_localhost() throws Exception {
+        InetAddress[] inetAddresses = InetAddress.getAllByName("ip6-localhost");
+        assertEquals(1, inetAddresses.length);
+        InetAddress inetAddress = inetAddresses[0];
+        assertEquals(LOOPBACK6_BYTES, "ip6-localhost", inetAddress);
+        assertTrue(inetAddress.isLoopbackAddress());
+    }
+
+    public void test_getByName_null() throws Exception {
+        InetAddress inetAddress = InetAddress.getByName("::1");
+
+        Set<InetAddress> expectedLoopbackAddresses =
+                createSet(Inet4Address.LOOPBACK, Inet6Address.LOOPBACK);
+        assertTrue(expectedLoopbackAddresses.contains(inetAddress));
+    }
+
+    public void test_getAllByName_null() throws Exception {
+        InetAddress[] inetAddresses = InetAddress.getAllByName(null);
+        assertEquals(2, inetAddresses.length);
+        Set<InetAddress> expectedLoopbackAddresses =
+                createSet(Inet4Address.LOOPBACK, Inet6Address.LOOPBACK);
+        assertEquals(expectedLoopbackAddresses, createSet(inetAddresses));
+    }
+
+    private static void assertEquals(
+        byte[] expectedAddressBytes, String expectedHostname, InetAddress actual) {
+        assertArrayEquals(expectedAddressBytes, actual.getAddress());
+        assertEquals(expectedHostname, actual.getHostName());
+
+    }
+
+    private static void assertArrayEquals(byte[] expected, byte[] actual) {
+        assertTrue("Expected=" + Arrays.toString(expected) + ", actual=" + Arrays.toString(actual),
+                Arrays.equals(expected, actual));
+    }
+
+    private static Set<InetAddress> createSet(InetAddress... members) {
+        return new HashSet<InetAddress>(Arrays.asList(members));
     }
 }
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
index 199164e..dabcdc6 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
@@ -46,6 +46,7 @@
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
 import javax.net.ServerSocketFactory;
+import javax.net.SocketFactory;
 import javax.net.ssl.HandshakeCompletedEvent;
 import javax.net.ssl.HandshakeCompletedListener;
 import javax.net.ssl.KeyManager;
@@ -1734,6 +1735,153 @@
         context.close();
     }
 
+    public void test_SSLSocket_ClientGetsAlertDuringHandshake_HasGoodExceptionMessage()
+            throws Exception {
+        TestSSLContext context = TestSSLContext.create();
+
+        final ServerSocket listener = ServerSocketFactory.getDefault().createServerSocket(0);
+        final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket(
+                context.host, listener.getLocalPort());
+        final Socket server = listener.accept();
+
+        ExecutorService executor = Executors.newFixedThreadPool(2);
+        Future<Void> c = executor.submit(new Callable<Void>() {
+            public Void call() throws Exception {
+                try {
+                    client.startHandshake();
+                    fail("Should receive handshake exception");
+                } catch (SSLHandshakeException expected) {
+                    assertFalse(expected.getMessage().contains("SSL_ERROR_ZERO_RETURN"));
+                    assertFalse(expected.getMessage().contains("You should never see this."));
+                }
+                return null;
+            }
+        });
+        Future<Void> s = executor.submit(new Callable<Void>() {
+            public Void call() throws Exception {
+                // Wait until the client sends something.
+                byte[] scratch = new byte[8192];
+                server.getInputStream().read(scratch);
+
+                // Write a bogus TLS alert:
+                // TLSv1.2 Record Layer: Alert (Level: Warning, Description: Protocol Version)
+                server.getOutputStream().write(new byte[] {
+                        0x15, 0x03, 0x03, 0x00, 0x02, 0x01, 0x46
+                });
+
+                // TLSv1.2 Record Layer: Alert (Level: Warning, Description: Close Notify)
+                server.getOutputStream().write(new byte[] {
+                        0x15, 0x03, 0x03, 0x00, 0x02, 0x01, 0x00
+                });
+
+                return null;
+            }
+        });
+
+
+        executor.shutdown();
+        c.get(5, TimeUnit.SECONDS);
+        s.get(5, TimeUnit.SECONDS);
+        client.close();
+        server.close();
+        listener.close();
+        context.close();
+    }
+
+    public void test_SSLSocket_ServerGetsAlertDuringHandshake_HasGoodExceptionMessage()
+            throws Exception {
+        TestSSLContext context = TestSSLContext.create();
+
+        final Socket client = SocketFactory.getDefault().createSocket(context.host, context.port);
+        final SSLSocket server = (SSLSocket) context.serverSocket.accept();
+
+        ExecutorService executor = Executors.newFixedThreadPool(2);
+        Future<Void> s = executor.submit(new Callable<Void>() {
+            public Void call() throws Exception {
+                try {
+                    server.startHandshake();
+                    fail("Should receive handshake exception");
+                } catch (SSLHandshakeException expected) {
+                    assertFalse(expected.getMessage().contains("SSL_ERROR_ZERO_RETURN"));
+                    assertFalse(expected.getMessage().contains("You should never see this."));
+                }
+                return null;
+            }
+        });
+        Future<Void> c = executor.submit(new Callable<Void>() {
+            public Void call() throws Exception {
+                // Send bogus ClientHello:
+                // TLSv1.2 Record Layer: Handshake Protocol: Client Hello
+                client.getOutputStream().write(new byte[] {
+                        (byte) 0x16, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0xb9,
+                        (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0xb5, (byte) 0x03,
+                        (byte) 0x03, (byte) 0x5a, (byte) 0x31, (byte) 0xba, (byte) 0x44,
+                        (byte) 0x24, (byte) 0xfd, (byte) 0xf0, (byte) 0x56, (byte) 0x46,
+                        (byte) 0xea, (byte) 0xee, (byte) 0x1c, (byte) 0x62, (byte) 0x8f,
+                        (byte) 0x18, (byte) 0x04, (byte) 0xbd, (byte) 0x1c, (byte) 0xbc,
+                        (byte) 0xbf, (byte) 0x6d, (byte) 0x84, (byte) 0x12, (byte) 0xe9,
+                        (byte) 0x94, (byte) 0xf5, (byte) 0x1c, (byte) 0x15, (byte) 0x3e,
+                        (byte) 0x79, (byte) 0x01, (byte) 0xe2, (byte) 0x00, (byte) 0x00,
+                        (byte) 0x28, (byte) 0xc0, (byte) 0x2b, (byte) 0xc0, (byte) 0x2c,
+                        (byte) 0xc0, (byte) 0x2f, (byte) 0xc0, (byte) 0x30, (byte) 0x00,
+                        (byte) 0x9e, (byte) 0x00, (byte) 0x9f, (byte) 0xc0, (byte) 0x09,
+                        (byte) 0xc0, (byte) 0x0a, (byte) 0xc0, (byte) 0x13, (byte) 0xc0,
+                        (byte) 0x14, (byte) 0x00, (byte) 0x33, (byte) 0x00, (byte) 0x39,
+                        (byte) 0xc0, (byte) 0x07, (byte) 0xc0, (byte) 0x11, (byte) 0x00,
+                        (byte) 0x9c, (byte) 0x00, (byte) 0x9d, (byte) 0x00, (byte) 0x2f,
+                        (byte) 0x00, (byte) 0x35, (byte) 0x00, (byte) 0x05, (byte) 0x00,
+                        (byte) 0xff, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x64,
+                        (byte) 0x00, (byte) 0x0b, (byte) 0x00, (byte) 0x04, (byte) 0x03,
+                        (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x00, (byte) 0x0a,
+                        (byte) 0x00, (byte) 0x34, (byte) 0x00, (byte) 0x32, (byte) 0x00,
+                        (byte) 0x0e, (byte) 0x00, (byte) 0x0d, (byte) 0x00, (byte) 0x19,
+                        (byte) 0x00, (byte) 0x0b, (byte) 0x00, (byte) 0x0c, (byte) 0x00,
+                        (byte) 0x18, (byte) 0x00, (byte) 0x09, (byte) 0x00, (byte) 0x0a,
+                        (byte) 0x00, (byte) 0x16, (byte) 0x00, (byte) 0x17, (byte) 0x00,
+                        (byte) 0x08, (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x07,
+                        (byte) 0x00, (byte) 0x14, (byte) 0x00, (byte) 0x15, (byte) 0x00,
+                        (byte) 0x04, (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x12,
+                        (byte) 0x00, (byte) 0x13, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+                        (byte) 0x02, (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x0f,
+                        (byte) 0x00, (byte) 0x10, (byte) 0x00, (byte) 0x11, (byte) 0x00,
+                        (byte) 0x0d, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x1e,
+                        (byte) 0x06, (byte) 0x01, (byte) 0x06, (byte) 0x02, (byte) 0x06,
+                        (byte) 0x03, (byte) 0x05, (byte) 0x01, (byte) 0x05, (byte) 0x02,
+                        (byte) 0x05, (byte) 0x03, (byte) 0x04, (byte) 0x01, (byte) 0x04,
+                        (byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x03, (byte) 0x01,
+                        (byte) 0x03, (byte) 0x02, (byte) 0x03, (byte) 0x03, (byte) 0x02,
+                        (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x03,
+                });
+
+                // Wait until the server sends something.
+                byte[] scratch = new byte[8192];
+                client.getInputStream().read(scratch);
+
+                // Write a bogus TLS alert:
+                // TLSv1.2 Record Layer: Alert (Level: Warning, Description:
+                // Protocol Version)
+                client.getOutputStream().write(new byte[] {
+                        0x15, 0x03, 0x03, 0x00, 0x02, 0x01, 0x46
+                });
+
+                // TLSv1.2 Record Layer: Alert (Level: Warning, Description:
+                // Close Notify)
+                client.getOutputStream().write(new byte[] {
+                        0x15, 0x03, 0x03, 0x00, 0x02, 0x01, 0x00
+                });
+
+                return null;
+            }
+        });
+
+        executor.shutdown();
+        c.get(5, TimeUnit.SECONDS);
+        s.get(5, TimeUnit.SECONDS);
+        client.close();
+        server.close();
+        context.close();
+    }
+
     /**
      * Not run by default by JUnit, but can be run by Vogar by
      * specifying it explicitly (or with main method below)