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)