1 /* 2 * Copyright (c) 2006, 2018, 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 /* @test 25 * @bug 8195160 26 * @summary Check no data is written to wrong socket channel during async closing. 27 * @requires (os.family == "linux") 28 * @library .. /test/lib 29 * @build RsocketTest 30 * @run main/othervm -Djava.net.preferIPv4Stack=true AsyncCloseChannel 31 */ 32 33 import java.io.*; 34 import java.nio.*; 35 import java.nio.channels.*; 36 import java.net.*; 37 import jdk.net.Sockets; 38 39 public class AsyncCloseChannel { 40 static volatile boolean failed = false; 41 static volatile boolean keepGoing = true; 42 static int maxAcceptCount = 20; 43 static volatile int acceptCount = 0; 44 static InetAddress host; 45 static int sensorPort; 46 static int targetPort; 47 48 public static void main(String args[]) throws Exception { 49 if (!RsocketTest.isRsocketAvailable()) 50 return; 51 52 host = InetAddress.getLocalHost(); 53 Thread ss = new SensorServer(); ss.start(); 54 Thread ts = new TargetServer(); ts.start(); 55 56 sensorPort = ((ServerThread)ss).server.getLocalPort(); 57 targetPort = ((ServerThread)ts).server.getLocalPort(); 58 59 Thread sc = new SensorClient(); sc.start(); 60 Thread tc = new TargetClient(); tc.start(); 61 62 while(acceptCount < maxAcceptCount && !failed) { 63 Thread.sleep(10); 64 } 65 keepGoing = false; 66 try { 67 ss.interrupt(); 68 ts.interrupt(); 69 sc.interrupt(); 70 tc.interrupt(); 71 } catch (Exception e) {} 72 if (failed) 73 throw new RuntimeException("AsyncCloseChannel2 failed after <" 74 + acceptCount + "> times of accept!"); 75 } 76 77 static class SensorServer extends ServerThread { 78 public void runEx() throws Exception { 79 while(keepGoing) { 80 try { 81 final Socket s = server.accept(); 82 new Thread() { 83 public void run() { 84 try { 85 int c = s.getInputStream().read(); 86 if(c != -1) { 87 // No data is ever written to the peer's socket! 88 System.err.println("Oops: read a character: " 89 + (char) c); 90 failed = true; 91 } 92 } catch (IOException ex) { 93 ex.printStackTrace(); 94 } finally { 95 closeIt(s); 96 } 97 } 98 }.start(); 99 } catch (IOException ex) { 100 System.err.println("Exception on sensor server " + ex.getMessage()); 101 } 102 } 103 } 104 } 105 106 static class TargetServer extends ServerThread { 107 public void runEx() throws Exception { 108 while (keepGoing) { 109 try { 110 final Socket s = server.accept(); 111 acceptCount++; 112 new Thread() { 113 public void run() { 114 boolean empty = true; 115 try { 116 for(;;) { 117 int c = s.getInputStream().read(); 118 if(c == -1) { 119 if(!empty) 120 break; 121 } 122 empty = false; 123 } 124 } catch (IOException ex) { 125 ex.printStackTrace(); 126 } finally { 127 closeIt(s); 128 } 129 } 130 }.start(); 131 } catch (IOException ex) { 132 System.err.println("Exception on target server " + ex.getMessage()); 133 } 134 } 135 } 136 } 137 138 static class SensorClient extends Thread { 139 private static boolean wake; 140 private static SensorClient theClient; 141 public void run() { 142 while (keepGoing) { 143 Socket s = null; 144 try { 145 s = Sockets.openRdmaSocket(); 146 synchronized(this) { 147 while(!wake && keepGoing) { 148 try { 149 wait(); 150 } catch (InterruptedException ex) { } 151 } 152 wake = false; 153 } 154 s.connect(new InetSocketAddress(host, sensorPort)); 155 try { 156 Thread.sleep(10); 157 } catch (InterruptedException ex) { } 158 } catch (IOException ex) { 159 System.err.println("Exception on sensor client " + ex.getMessage()); 160 } finally { 161 if(s != null) { 162 try { 163 s.close(); 164 } catch(IOException ex) { ex.printStackTrace();} 165 } 166 } 167 } 168 } 169 170 public SensorClient() { 171 theClient = this; 172 } 173 174 public static void wakeMe() { 175 synchronized(theClient) { 176 wake = true; 177 theClient.notify(); 178 } 179 } 180 } 181 182 static class TargetClient extends Thread { 183 volatile boolean ready = false; 184 public void run() { 185 while(keepGoing) { 186 try { 187 final SocketChannel s = Sockets.openRdmaSocketChannel(); 188 s.connect(new InetSocketAddress(host, targetPort)); 189 s.finishConnect(); 190 ready = false; 191 Thread t = new Thread() { 192 public void run() { 193 ByteBuffer b = ByteBuffer.allocate(1); 194 try { 195 for(;;) { 196 b.clear(); 197 b.put((byte) 'A'); 198 b.flip(); 199 s.write(b); 200 ready = true; 201 } 202 } catch (IOException ex) { 203 if(!(ex instanceof ClosedChannelException)) 204 System.err.println("Exception in target client child " 205 + ex.toString()); 206 } 207 } 208 }; 209 t.start(); 210 while(!ready && keepGoing) { 211 try { 212 Thread.sleep(10); 213 } catch (InterruptedException ex) {} 214 } 215 s.close(); 216 SensorClient.wakeMe(); 217 t.join(); 218 } catch (IOException ex) { 219 System.err.println("Exception in target client parent " 220 + ex.getMessage()); 221 } catch (InterruptedException ex) {} 222 } 223 } 224 } 225 226 static abstract class ServerThread extends Thread { 227 ServerSocket server; 228 public ServerThread() { 229 super(); 230 try { 231 server = Sockets.openRdmaServerSocket(); 232 server.bind(new InetSocketAddress(host, 0)); 233 } catch (IOException ex) { 234 ex.printStackTrace(); 235 } 236 } 237 238 public void interrupt() { 239 super.interrupt(); 240 if (server != null) { 241 try { 242 server.close(); 243 } catch (IOException ex) { 244 ex.printStackTrace(); 245 } 246 } 247 } 248 public void run() { 249 try { 250 runEx(); 251 } catch (Exception ex) { 252 ex.printStackTrace(); 253 } 254 } 255 256 abstract void runEx() throws Exception; 257 } 258 259 public static void closeIt(Socket s) { 260 try { 261 if(s != null) 262 s.close(); 263 } catch (IOException ex) { } 264 } 265 }