1 /* 2 * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * @test 26 * @run testng ConnectionReset 27 * @run testng/othervm -Djdk.net.usePlainSocketImpl ConnectionReset 28 * @summary Test behavior of read and available when a connection is reset 29 */ 30 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.net.InetAddress; 34 import java.net.InetSocketAddress; 35 import java.net.ServerSocket; 36 import java.net.Socket; 37 38 import org.testng.annotations.Test; 39 import static org.testng.Assert.*; 40 41 @Test 42 public class ConnectionReset { 43 44 static final int REPEAT_COUNT = 5; 45 46 /** 47 * Tests available before read when there are no bytes to read 48 */ 49 public void testAvailableBeforeRead1() throws IOException { 50 System.out.println("testAvailableBeforeRead1"); 51 withResetConnection(null, s -> { 52 InputStream in = s.getInputStream(); 53 for (int i=0; i<REPEAT_COUNT; i++) { 54 int bytesAvailable = in.available(); 55 System.out.format("available => %d%n", bytesAvailable); 56 assertTrue(bytesAvailable == 0); 57 try { 58 int bytesRead = in.read(); 59 if (bytesRead == -1) { 60 System.out.println("read => EOF"); 61 } else { 62 System.out.println("read => 1 byte"); 63 } 64 assertTrue(false); 65 } catch (IOException ioe) { 66 System.out.format("read => %s (expected)%n", ioe); 67 } 68 } 69 }); 70 } 71 72 /** 73 * Tests available before read when there are bytes to read 74 */ 75 public void testAvailableBeforeRead2() throws IOException { 76 System.out.println("testAvailableBeforeRead2"); 77 byte[] data = { 1, 2, 3 }; 78 withResetConnection(data, s -> { 79 InputStream in = s.getInputStream(); 80 int remaining = data.length; 81 for (int i=0; i<REPEAT_COUNT; i++) { 82 int bytesAvailable = in.available(); 83 System.out.format("available => %d%n", bytesAvailable); 84 assertTrue(bytesAvailable <= remaining); 85 try { 86 int bytesRead = in.read(); 87 if (bytesRead == -1) { 88 System.out.println("read => EOF"); 89 assertTrue(false); 90 } else { 91 System.out.println("read => 1 byte"); 92 assertTrue(remaining > 0); 93 remaining--; 94 } 95 } catch (IOException ioe) { 96 System.out.format("read => %s%n", ioe); 97 remaining = 0; 98 } 99 } 100 }); 101 } 102 103 /** 104 * Tests read before available when there are no bytes to read 105 */ 106 public void testReadBeforeAvailable1() throws IOException { 107 System.out.println("testReadBeforeAvailable1"); 108 withResetConnection(null, s -> { 109 InputStream in = s.getInputStream(); 110 for (int i=0; i<REPEAT_COUNT; i++) { 111 try { 112 int bytesRead = in.read(); 113 if (bytesRead == -1) { 114 System.out.println("read => EOF"); 115 } else { 116 System.out.println("read => 1 byte"); 117 } 118 assertTrue(false); 119 } catch (IOException ioe) { 120 System.out.format("read => %s (expected)%n", ioe); 121 } 122 int bytesAvailable = in.available(); 123 System.out.format("available => %d%n", bytesAvailable); 124 assertTrue(bytesAvailable == 0); 125 } 126 }); 127 } 128 129 /** 130 * Tests read before available when there are bytes to read 131 */ 132 public void testReadBeforeAvailable2() throws IOException { 133 System.out.println("testReadBeforeAvailable2"); 134 byte[] data = { 1, 2, 3 }; 135 withResetConnection(data, s -> { 136 InputStream in = s.getInputStream(); 137 int remaining = data.length; 138 for (int i=0; i<REPEAT_COUNT; i++) { 139 try { 140 int bytesRead = in.read(); 141 if (bytesRead == -1) { 142 System.out.println("read => EOF"); 143 assertTrue(false); 144 } else { 145 System.out.println("read => 1 byte"); 146 assertTrue(remaining > 0); 147 remaining--; 148 } 149 } catch (IOException ioe) { 150 System.out.format("read => %s%n", ioe); 151 remaining = 0; 152 } 153 int bytesAvailable = in.available(); 154 System.out.format("available => %d%n", bytesAvailable); 155 assertTrue(bytesAvailable <= remaining); 156 } 157 }); 158 } 159 160 /** 161 * Tests available and read on a socket closed after connection reset 162 */ 163 public void testAfterClose() throws IOException { 164 System.out.println("testAfterClose"); 165 withResetConnection(null, s -> { 166 InputStream in = s.getInputStream(); 167 try { 168 in.read(); 169 assertTrue(false); 170 } catch (IOException ioe) { 171 // expected 172 } 173 s.close(); 174 try { 175 int bytesAvailable = in.available(); 176 System.out.format("available => %d%n", bytesAvailable); 177 assertTrue(false); 178 } catch (IOException ioe) { 179 System.out.format("available => %s (expected)%n", ioe); 180 } 181 try { 182 int n = in.read(); 183 System.out.format("read => %d%n", n); 184 assertTrue(false); 185 } catch (IOException ioe) { 186 System.out.format("read => %s (expected)%n", ioe); 187 } 188 }); 189 } 190 191 interface ThrowingConsumer<T> { 192 void accept(T t) throws IOException; 193 } 194 195 /** 196 * Invokes a consumer with a Socket connected to a peer that has closed the 197 * connection with a "connection reset". The peer sends the given data bytes 198 * before closing (when data is not null). 199 */ 200 static void withResetConnection(byte[] data, ThrowingConsumer<Socket> consumer) 201 throws IOException 202 { 203 var loopback = InetAddress.getLoopbackAddress(); 204 try (var listener = new ServerSocket()) { 205 listener.bind(new InetSocketAddress(loopback, 0)); 206 try (var socket = new Socket()) { 207 socket.connect(listener.getLocalSocketAddress()); 208 try (Socket peer = listener.accept()) { 209 if (data != null) { 210 peer.getOutputStream().write(data); 211 } 212 peer.setSoLinger(true, 0); 213 } 214 consumer.accept(socket); 215 } 216 } 217 } 218 }