/* * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * 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. * * 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. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* @test * @requires (os.family == "linux" | os.family == "mac") * @bug 8203937 * @summary Test reading bytes from a socket after the connection has been * reset by the peer */ import java.io.IOException; import java.io.PrintStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; /** * This test exercises platform specific and unspecified behavior. It exists * only to ensure that the behavior doesn't change between JDK releases. */ public class ReadAfterReset { private static final PrintStream out = System.out; // number of bytes to write before the connection reset private static final int NUM_BYTES_TO_WRITE = 1000; public static void main(String[] args) throws IOException { try (ServerSocket ss = new ServerSocket()) { ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); /** * Connect to the server which will write some bytes and reset the * connection. The client then attempts to read the bytes sent by * the server before it closed the connection. */ out.println("Test connection ..."); try (Socket s = new Socket()) { s.connect(ss.getLocalSocketAddress()); int nwrote = acceptAndResetConnection(ss); int nread = readUntilIOException(s); if (nread != nwrote) { throw new RuntimeException("Client read " + nread + ", expected " + nwrote); } } /** * Connect to the server which will write some bytes and reset the * connection. The client then writes to its end of the connection, * failing as the connection is reset. It then attempts to read the * bytes sent by the server before it closed the connection. */ out.println(); out.println("Test connection ..."); try (Socket s = new Socket()) { s.connect(ss.getLocalSocketAddress()); int nwrote = acceptAndResetConnection(ss); writeUntilIOException(s); int nread = readUntilIOException(s); if (nread != nwrote) { throw new RuntimeException("Client read " + nread + ", expected " + nwrote); } } } } /** * Accept a connection, write bytes, and then reset the connection */ static int acceptAndResetConnection(ServerSocket ss) throws IOException { int count = NUM_BYTES_TO_WRITE; try (Socket peer = ss.accept()) { peer.getOutputStream().write(new byte[count]); peer.setSoLinger(true, 0); out.format("Server wrote %d bytes and reset connection%n", count); } return count; } /** * Write bytes to a socket until I/O exception is thrown */ static void writeUntilIOException(Socket s) { try { byte[] bytes = new byte[100]; while (true) { s.getOutputStream().write(bytes); out.format("Client wrote %d bytes%n", bytes.length); } } catch (IOException ioe) { out.format("Client write failed: %s (expected)%n", ioe); } } /** * Read bytes from a socket until I/O exception is thrown. * * @return the number of bytes read before the I/O exception was thrown */ static int readUntilIOException(Socket s) { int nread = 0; try { byte[] bytes = new byte[100]; while (true) { int n = s.getInputStream().read(bytes); if (n < 0) { out.println("Client read EOF"); break; } else { out.format("Client read %s bytes%n", n); nread += n; } } } catch (IOException ioe) { out.format("Client read failed: %s (expected)%n", ioe); } return nread; } }