package org.eclipse.jetty.io.nio; import java.io.File; import java.io.IOException; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLSocket; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest { static SslContextFactory __sslCtxFactory=new SslContextFactory(); @BeforeClass public static void initSslEngine() throws Exception { File keystore = MavenTestingUtils.getTestResourceFile("keystore"); __sslCtxFactory.setKeyStorePath(keystore.getAbsolutePath()); __sslCtxFactory.setKeyStorePassword("storepwd"); __sslCtxFactory.setKeyManagerPassword("keypwd"); __sslCtxFactory.start(); } @Override protected Socket newClient() throws IOException { SSLSocket socket = __sslCtxFactory.newSslSocket(); socket.connect(_connector.socket().getLocalSocketAddress()); return socket; } @Override protected AsyncConnection newConnection(SocketChannel channel, EndPoint endpoint) { SSLEngine engine = __sslCtxFactory.newSslEngine(); engine.setUseClientMode(false); SslConnection connection = new SslConnection(engine,endpoint); AsyncConnection delegate = super.newConnection(channel,connection.getSslEndPoint()); connection.getSslEndPoint().setConnection(delegate); return connection; } @Test @Override public void testEcho() throws Exception { super.testEcho(); } @Test @Override public void testShutdown() throws Exception { // SSL does not do half closes } @Test public void testTcpClose() throws Exception { // This test replaces SSLSocket() with a very manual SSL client // so we can close TCP underneath SSL. SocketChannel client = SocketChannel.open(_connector.socket().getLocalSocketAddress()); client.socket().setSoTimeout(500); SocketChannel server = _connector.accept(); server.configureBlocking(false); _manager.register(server); SSLEngine engine = __sslCtxFactory.newSslEngine(); engine.setUseClientMode(true); engine.beginHandshake(); ByteBuffer appOut = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize()); ByteBuffer sslOut = ByteBuffer.allocate(engine.getSession().getPacketBufferSize()*2); ByteBuffer appIn = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize()); ByteBuffer sslIn = ByteBuffer.allocate(engine.getSession().getPacketBufferSize()*2); boolean debug=false; if (debug) System.err.println(engine.getHandshakeStatus()); int loop=20; while (engine.getHandshakeStatus()!=HandshakeStatus.NOT_HANDSHAKING) { if (--loop==0) throw new IllegalStateException(); if (engine.getHandshakeStatus()==HandshakeStatus.NEED_WRAP) { if (debug) System.err.printf("sslOut %d-%d-%d%n",sslOut.position(),sslOut.limit(),sslOut.capacity()); if (debug) System.err.printf("appOut %d-%d-%d%n",appOut.position(),appOut.limit(),appOut.capacity()); SSLEngineResult result =engine.wrap(appOut,sslOut); if (debug) System.err.println(result); sslOut.flip(); int flushed=client.write(sslOut); if (debug) System.err.println("out="+flushed); sslOut.clear(); } if (engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP) { if (debug) System.err.printf("sslIn %d-%d-%d%n",sslIn.position(),sslIn.limit(),sslIn.capacity()); if (sslIn.position()==0) { int filled=client.read(sslIn); if (debug) System.err.println("in="+filled); } sslIn.flip(); if (debug) System.err.printf("sslIn %d-%d-%d%n",sslIn.position(),sslIn.limit(),sslIn.capacity()); SSLEngineResult result =engine.unwrap(sslIn,appIn); if (debug) System.err.println(result); if (debug) System.err.printf("sslIn %d-%d-%d%n",sslIn.position(),sslIn.limit(),sslIn.capacity()); if (sslIn.hasRemaining()) sslIn.compact(); else sslIn.clear(); if (debug) System.err.printf("sslIn %d-%d-%d%n",sslIn.position(),sslIn.limit(),sslIn.capacity()); } if (engine.getHandshakeStatus()==HandshakeStatus.NEED_TASK) { Runnable task; while ((task=engine.getDelegatedTask())!=null) task.run(); if (debug) System.err.println(engine.getHandshakeStatus()); } } if (debug) System.err.println("\nSay Hello"); // write a message appOut.put("HelloWorld".getBytes("UTF-8")); appOut.flip(); SSLEngineResult result =engine.wrap(appOut,sslOut); if (debug) System.err.println(result); sslOut.flip(); int flushed=client.write(sslOut); if (debug) System.err.println("out="+flushed); sslOut.clear(); appOut.clear(); // read the response int filled=client.read(sslIn); if (debug) System.err.println("in="+filled); sslIn.flip(); result =engine.unwrap(sslIn,appIn); if (debug) System.err.println(result); if (sslIn.hasRemaining()) sslIn.compact(); else sslIn.clear(); appIn.flip(); String reply= new String(appIn.array(),appIn.arrayOffset(),appIn.remaining()); appIn.clear(); Assert.assertEquals("HelloWorld",reply); SelectorManager.LOG.info("javax.net.ssl.SSLException: Inbound closed... is expected soon"); if (debug) System.err.println("\nSudden Death"); client.socket().shutdownOutput(); filled=client.read(sslIn); Assert.assertEquals(-1,filled); } @Test public void testStress() throws Exception { super.testStress(); } }