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