1/* 2 * Copyright (c) 2012, 2017, 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 7184932 26 * @summary Test asynchronous close and interrupt of timed socket adapter methods 27 * @key randomness intermittent 28 */ 29 30import java.io.*; 31import java.nio.*; 32import java.nio.channels.*; 33import java.nio.channels.spi.AbstractSelectableChannel; 34import java.net.*; 35import java.util.concurrent.Callable; 36import java.util.concurrent.Executors; 37import java.util.concurrent.ScheduledExecutorService; 38import java.util.concurrent.TimeUnit; 39import java.util.concurrent.atomic.AtomicBoolean; 40import java.util.Random; 41 42 43public class AdaptorCloseAndInterrupt { 44 private static final ScheduledExecutorService pool = 45 Executors.newScheduledThreadPool(1); 46 final ServerSocketChannel listener; 47 final DatagramChannel peer; 48 final int port; 49 50 final AtomicBoolean isClosed = new AtomicBoolean(); 51 final AtomicBoolean isInterrupted = new AtomicBoolean(); 52 53 public AdaptorCloseAndInterrupt() { 54 listener = null; 55 peer = null; 56 port = -1; 57 } 58 59 public AdaptorCloseAndInterrupt(ServerSocketChannel listener) { 60 this.listener = listener; 61 this.port = listener.socket().getLocalPort(); 62 this.peer = null; 63 } 64 65 public AdaptorCloseAndInterrupt(DatagramChannel listener) { 66 this.peer = listener; 67 this.port = peer.socket().getLocalPort(); 68 this.listener = null; 69 } 70 71 public static void main(String args[]) throws Exception { 72 try { 73 try (ServerSocketChannel listener = ServerSocketChannel.open()) { 74 listener.socket().bind(null); 75 new AdaptorCloseAndInterrupt(listener).scReadAsyncClose(); 76 new AdaptorCloseAndInterrupt(listener).scReadAsyncInterrupt(); 77 } 78 79 try (DatagramChannel peer = DatagramChannel.open()) { 80 peer.socket().bind(null); 81 new AdaptorCloseAndInterrupt(peer).dcReceiveAsyncClose(); 82 new AdaptorCloseAndInterrupt(peer).dcReceiveAsyncInterrupt(); 83 } 84 85 new AdaptorCloseAndInterrupt().ssAcceptAsyncClose(); 86 new AdaptorCloseAndInterrupt().ssAcceptAsyncInterrupt(); 87 } finally { 88 pool.shutdown(); 89 } 90 System.out.println("Test Passed"); 91 } 92 93 void scReadAsyncClose() throws IOException { 94 try { 95 SocketChannel sc = SocketChannel.open(new InetSocketAddress( 96 "127.0.0.1", port)); 97 sc.socket().setSoTimeout(30*1000); 98 99 doAsyncClose(sc); 100 101 try { 102 sc.socket().getInputStream().read(new byte[100]); 103 System.err.format("close() was invoked: %s%n", isClosed.get()); 104 throw new RuntimeException("read should not have completed"); 105 } catch (ClosedChannelException expected) {} 106 107 if (!sc.socket().isClosed()) 108 throw new RuntimeException("socket is not closed"); 109 } finally { 110 // accept connection and close it. 111 listener.accept().close(); 112 } 113 } 114 115 void scReadAsyncInterrupt() throws IOException { 116 try { 117 final SocketChannel sc = SocketChannel.open(new InetSocketAddress( 118 "127.0.0.1", port)); 119 sc.socket().setSoTimeout(30*1000); 120 121 doAsyncInterrupt(); 122 123 try { 124 sc.socket().getInputStream().read(new byte[100]); 125 throw new RuntimeException("read should not have completed"); 126 } catch (ClosedByInterruptException expected) { 127 System.out.format("interrupt() was invoked: %s%n", 128 isInterrupted.get()); 129 System.out.format("scReadAsyncInterrupt was interrupted: %s%n", 130 Thread.currentThread().interrupted()); 131 } 132 133 if (!sc.socket().isClosed()) 134 throw new RuntimeException("socket is not closed"); 135 } finally { 136 // accept connection and close it. 137 listener.accept().close(); 138 } 139 } 140 141 void dcReceiveAsyncClose() throws IOException { 142 DatagramChannel dc = DatagramChannel.open(); 143 dc.connect(new InetSocketAddress( 144 "127.0.0.1", port)); 145 dc.socket().setSoTimeout(30*1000); 146 147 doAsyncClose(dc); 148 149 try { 150 dc.socket().receive(new DatagramPacket(new byte[100], 100)); 151 System.err.format("close() was invoked: %s%n", isClosed.get()); 152 throw new RuntimeException("receive should not have completed"); 153 } catch (ClosedChannelException expected) {} 154 155 if (!dc.socket().isClosed()) 156 throw new RuntimeException("socket is not closed"); 157 } 158 159 void dcReceiveAsyncInterrupt() throws IOException { 160 DatagramChannel dc = DatagramChannel.open(); 161 dc.connect(new InetSocketAddress( 162 "127.0.0.1", port)); 163 dc.socket().setSoTimeout(30*1000); 164 165 doAsyncInterrupt(); 166 167 try { 168 dc.socket().receive(new DatagramPacket(new byte[100], 100)); 169 throw new RuntimeException("receive should not have completed"); 170 } catch (ClosedByInterruptException expected) { 171 System.out.format("interrupt() was invoked: %s%n", 172 isInterrupted.get()); 173 System.out.format("dcReceiveAsyncInterrupt was interrupted: %s%n", 174 Thread.currentThread().interrupted()); 175 } catch (SocketTimeoutException unexpected) { 176 System.err.format("Receive thread interrupt invoked: %s%n", 177 isInterrupted.get()); 178 System.err.format("Receive thread was interrupted: %s%n", 179 Thread.currentThread().isInterrupted()); 180 throw unexpected; 181 } 182 183 if (!dc.socket().isClosed()) 184 throw new RuntimeException("socket is not closed"); 185 } 186 187 void ssAcceptAsyncClose() throws IOException { 188 ServerSocketChannel ssc = ServerSocketChannel.open(); 189 ssc.socket().bind(null); 190 ssc.socket().setSoTimeout(30*1000); 191 192 doAsyncClose(ssc); 193 194 try { 195 ssc.socket().accept(); 196 System.err.format("close() was invoked: %s%n", isClosed.get()); 197 throw new RuntimeException("accept should not have completed"); 198 } catch (ClosedChannelException expected) {} 199 200 if (!ssc.socket().isClosed()) 201 throw new RuntimeException("socket is not closed"); 202 } 203 204 void ssAcceptAsyncInterrupt() throws IOException { 205 ServerSocketChannel ssc = ServerSocketChannel.open(); 206 ssc.socket().bind(null); 207 ssc.socket().setSoTimeout(30*1000); 208 209 doAsyncInterrupt(); 210 211 try { 212 ssc.socket().accept(); 213 throw new RuntimeException("accept should not have completed"); 214 } catch (ClosedByInterruptException expected) { 215 System.out.format("interrupt() was invoked: %s%n", 216 isInterrupted.get()); 217 System.out.format("ssAcceptAsyncInterrupt was interrupted: %s%n", 218 Thread.currentThread().interrupted()); 219 } 220 221 if (!ssc.socket().isClosed()) 222 throw new RuntimeException("socket is not closed"); 223 } 224 225 void doAsyncClose(final AbstractSelectableChannel sc) { 226 AdaptorCloseAndInterrupt.pool.schedule(new Callable<Void>() { 227 public Void call() throws Exception { 228 sc.close(); 229 isClosed.set(true); 230 return null; 231 } 232 }, new Random().nextInt(1000), TimeUnit.MILLISECONDS); 233 } 234 235 void doAsyncInterrupt() { 236 final Thread current = Thread.currentThread(); 237 AdaptorCloseAndInterrupt.pool.schedule(new Callable<Void>() { 238 public Void call() throws Exception { 239 current.interrupt(); 240 isInterrupted.set(true); 241 return null; 242 } 243 }, new Random().nextInt(1000), TimeUnit.MILLISECONDS); 244 } 245 246} 247