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 }