/** Closes the write half of the stream. */ @Override public void closeWrite() throws IOException { if (_isCloseWrite) { return; } _isCloseWrite = true; // OutputStream os = _os; // _os = null; boolean isShutdownOutput = false; // since the output stream is opened lazily, we might // need to open it if (_s != null) { try { _s.shutdownOutput(); isShutdownOutput = true; } catch (UnsupportedOperationException e) { log.log(Level.FINEST, e.toString(), e); } catch (Exception e) { log.finer(e.toString()); log.log(Level.FINEST, e.toString(), e); } } /* // SSLSocket doesn't support shutdownOutput() if (! isShutdownOutput && os != null) { os.close(); } */ }
public static void main(String[] args) throws Exception { ServerSocketChannel ssc = ServerSocketChannel.open().bind(new InetSocketAddress(0)); try { InetAddress lh = InetAddress.getLocalHost(); int port = ((InetSocketAddress) (ssc.getLocalAddress())).getPort(); SocketAddress remote = new InetSocketAddress(lh, port); // Test SocketChannel shutdownXXX SocketChannel sc; sc = SocketChannel.open(remote); try { acceptAndReset(ssc); sc.shutdownInput(); sc.shutdownOutput(); } finally { sc.close(); } // Test Socket adapter shutdownXXX and isShutdownInput sc = SocketChannel.open(remote); try { acceptAndReset(ssc); boolean before = sc.socket().isInputShutdown(); sc.socket().shutdownInput(); boolean after = sc.socket().isInputShutdown(); if (before || !after) throw new RuntimeException("Before and after test failed"); sc.socket().shutdownOutput(); } finally { sc.close(); } } finally { ssc.close(); } }
@Test public void testGentleCloseDuringHandshake() throws Exception { InetSocketAddress address = startServer(version, null); SslContextFactory sslContextFactory = newSslContextFactory(); sslContextFactory.start(); SSLEngine sslEngine = sslContextFactory.newSSLEngine(address); sslEngine.setUseClientMode(true); NextProtoNego.put( sslEngine, new NextProtoNego.ClientProvider() { @Override public boolean supports() { return true; } @Override public void unsupported() {} @Override public String selectProtocol(List<String> protocols) { return null; } }); sslEngine.beginHandshake(); ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize()); sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted); encrypted.flip(); try (SocketChannel channel = SocketChannel.open(address)) { // Send ClientHello, immediately followed by TLS Close Alert and then by FIN channel.write(encrypted); sslEngine.closeOutbound(); encrypted.clear(); sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted); encrypted.flip(); channel.write(encrypted); channel.shutdownOutput(); // Read ServerHello from server encrypted.clear(); int read = channel.read(encrypted); encrypted.flip(); Assert.assertTrue(read > 0); // Cannot decrypt, as the SSLEngine has been already closed // Now if we read more, we should either read the TLS Close Alert, or directly -1 encrypted.clear(); read = channel.read(encrypted); // Sending a TLS Close Alert during handshake results in an exception when // unwrapping that the server react to by closing the connection abruptly. Assert.assertTrue(read < 0); } }
@Test public void testAbruptCloseDuringHandshake() throws Exception { InetSocketAddress address = startServer(version, null); SslContextFactory sslContextFactory = newSslContextFactory(); sslContextFactory.start(); SSLEngine sslEngine = sslContextFactory.newSSLEngine(address); sslEngine.setUseClientMode(true); NextProtoNego.put( sslEngine, new NextProtoNego.ClientProvider() { @Override public boolean supports() { return true; } @Override public void unsupported() {} @Override public String selectProtocol(List<String> protocols) { return null; } }); sslEngine.beginHandshake(); ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize()); sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted); encrypted.flip(); try (SocketChannel channel = SocketChannel.open(address)) { // Send ClientHello, immediately followed by FIN (no TLS Close Alert) channel.write(encrypted); channel.shutdownOutput(); // Read ServerHello from server encrypted.clear(); int read = channel.read(encrypted); encrypted.flip(); Assert.assertTrue(read > 0); ByteBuffer decrypted = ByteBuffer.allocate(sslEngine.getSession().getApplicationBufferSize()); sslEngine.unwrap(encrypted, decrypted); // Now if we read more, we should either read the TLS Close Alert, or directly -1 encrypted.clear(); read = channel.read(encrypted); // Since we have close the connection abruptly, the server also does so Assert.assertTrue(read < 0); } }
@Override public SocketChannel shutdownOutput() throws IOException { socketChannel = socketChannel.shutdownOutput(); return this; }