1 /* 2 * Copyright (c) 2019, 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 * @requires os.family != "solaris" 27 * @run testng ConnectionReset 28 * @summary Test behavior of SocketChannel.read and the Socket adaptor read 29 * and available methods when a connection is reset 30 */ 31 32 import java.io.InputStream; 33 import java.io.IOException; 34 import java.net.InetAddress; 35 import java.net.InetSocketAddress; 36 import java.net.ServerSocket; 37 import java.net.Socket; 38 import java.nio.ByteBuffer; 39 import java.nio.channels.SocketChannel; 40 import java.lang.reflect.Method; 41 42 import org.testng.annotations.Test; 43 import static org.testng.Assert.*; 44 45 @Test 46 public class ConnectionReset { 47 48 static final int REPEAT_COUNT = 5; 49 50 /** 51 * Tests SocketChannel.read when the connection is reset and there are no 52 * bytes to read. 53 */ 54 public void testSocketChannelReadNoData() throws IOException { 55 System.out.println("testSocketChannelReadNoData"); 56 withResetConnection(null, sc -> { 57 ByteBuffer bb = ByteBuffer.allocate(100); 58 for (int i=0; i<REPEAT_COUNT; i++) { 59 try { 60 sc.read(bb); 61 assertTrue(false); 62 } catch (IOException ioe) { 63 System.out.format("read => %s (expected)%n", ioe); 64 } 65 } 66 }); 67 } 68 69 /** 70 * Tests SocketChannel.read when the connection is reset and there are bytes 71 * to read. 72 */ 73 public void testSocketChannelReadData() throws IOException { 74 System.out.println("testSocketChannelReadData"); 75 byte[] data = { 1, 2, 3 }; 76 withResetConnection(data, sc -> { 77 int remaining = data.length; 78 ByteBuffer bb = ByteBuffer.allocate(remaining + 100); 79 for (int i=0; i<REPEAT_COUNT; i++) { 80 try { 81 int bytesRead = sc.read(bb); 82 if (bytesRead == -1) { 83 System.out.println("read => EOF"); 84 } else { 85 System.out.println("read => " + bytesRead + " byte(s)"); 86 } 87 assertTrue(bytesRead > 0); 88 remaining -= bytesRead; 89 assertTrue(remaining >= 0); 90 } catch (IOException ioe) { 91 System.out.format("read => %s%n", ioe); 92 remaining = 0; 93 } 94 } 95 }); 96 } 97 98 99 /** 100 * Tests available before Socket read when the connection is reset and there 101 * are no bytes to read. 102 */ 103 public void testAvailableBeforeSocketReadNoData() throws IOException { 104 System.out.println("testAvailableBeforeSocketReadNoData"); 105 withResetConnection(null, sc -> { 106 Socket s = sc.socket(); 107 InputStream in = s.getInputStream(); 108 for (int i=0; i<REPEAT_COUNT; i++) { 109 int bytesAvailable = in.available(); 110 System.out.format("available => %d%n", bytesAvailable); 111 assertTrue(bytesAvailable == 0); 112 try { 113 int bytesRead = in.read(); 114 if (bytesRead == -1) { 115 System.out.println("read => EOF"); 116 } else { 117 System.out.println("read => 1 byte"); 118 } 119 assertTrue(false); 120 } catch (IOException ioe) { 121 System.out.format("read => %s (expected)%n", ioe); 122 } 123 } 124 }); 125 } 126 127 /** 128 * Tests available before Socket read when the connection is reset and there 129 * are bytes to read. 130 */ 131 public void testAvailableBeforeSocketReadData() throws IOException { 132 System.out.println("testAvailableBeforeSocketReadData"); 133 byte[] data = { 1, 2, 3 }; 134 withResetConnection(data, sc -> { 135 Socket s = sc.socket(); 136 InputStream in = s.getInputStream(); 137 int remaining = data.length; 138 for (int i=0; i<REPEAT_COUNT; i++) { 139 int bytesAvailable = in.available(); 140 System.out.format("available => %d%n", bytesAvailable); 141 assertTrue(bytesAvailable <= remaining); 142 try { 143 int bytesRead = in.read(); 144 if (bytesRead == -1) { 145 System.out.println("read => EOF"); 146 assertTrue(false); 147 } else { 148 System.out.println("read => 1 byte"); 149 assertTrue(remaining > 0); 150 remaining--; 151 } 152 } catch (IOException ioe) { 153 System.out.format("read => %s%n", ioe); 154 remaining = 0; 155 } 156 } 157 }); 158 } 159 160 /** 161 * Tests Socket read before available when the connection is reset and there 162 * are no bytes to read. 163 */ 164 public void testSocketReadNoDataBeforeAvailable() throws IOException { 165 System.out.println("testSocketReadNoDataBeforeAvailable"); 166 withResetConnection(null, sc -> { 167 Socket s = sc.socket(); 168 InputStream in = s.getInputStream(); 169 for (int i=0; i<REPEAT_COUNT; i++) { 170 try { 171 int bytesRead = in.read(); 172 if (bytesRead == -1) { 173 System.out.println("read => EOF"); 174 } else { 175 System.out.println("read => 1 byte"); 176 } 177 assertTrue(false); 178 } catch (IOException ioe) { 179 System.out.format("read => %s (expected)%n", ioe); 180 } 181 int bytesAvailable = in.available(); 182 System.out.format("available => %d%n", bytesAvailable); 183 assertTrue(bytesAvailable == 0); 184 } 185 }); 186 } 187 188 /** 189 * Tests Socket read before available when the connection is reset and there 190 * are bytes to read. 191 */ 192 public void testSocketReadDataBeforeAvailable() throws IOException { 193 System.out.println("testSocketReadDataBeforeAvailable"); 194 byte[] data = { 1, 2, 3 }; 195 withResetConnection(data, sc -> { 196 Socket s = sc.socket(); 197 InputStream in = s.getInputStream(); 198 int remaining = data.length; 199 for (int i=0; i<REPEAT_COUNT; i++) { 200 try { 201 int bytesRead = in.read(); 202 if (bytesRead == -1) { 203 System.out.println("read => EOF"); 204 assertTrue(false); 205 } else { 206 System.out.println("read => 1 byte"); 207 assertTrue(remaining > 0); 208 remaining--; 209 } 210 } catch (IOException ioe) { 211 System.out.format("read => %s%n", ioe); 212 remaining = 0; 213 } 214 int bytesAvailable = in.available(); 215 System.out.format("available => %d%n", bytesAvailable); 216 assertTrue(bytesAvailable <= remaining); 217 } 218 }); 219 } 220 221 interface ThrowingConsumer<T> { 222 void accept(T t) throws IOException; 223 } 224 225 /** 226 * Invokes a consumer with a SocketChannel connected to a peer that has closed 227 * the connection with a "connection reset". The peer sends the given data 228 * bytes before closing (when data is not null). 229 */ 230 static void withResetConnection(byte[] data, ThrowingConsumer<SocketChannel> consumer) 231 throws IOException 232 { 233 var loopback = InetAddress.getLoopbackAddress(); 234 try (var listener = new ServerSocket()) { 235 listener.bind(new InetSocketAddress(loopback, 0)); 236 try (var sc = SocketChannel.open()) { 237 sc.connect(listener.getLocalSocketAddress()); 238 try (Socket peer = listener.accept()) { 239 if (data != null) { 240 peer.getOutputStream().write(data); 241 } 242 peer.setSoLinger(true, 0); 243 } 244 consumer.accept(sc); 245 } 246 } 247 } 248 }