1 /* 2 * Copyright (c) 2002, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 */ 28 29 package sun.nio.ch; 30 31 import java.io.IOException; 32 import java.net.InetAddress; 33 import java.net.InetSocketAddress; 34 import java.nio.*; 35 import java.nio.channels.*; 36 import java.nio.channels.spi.*; 37 import java.security.AccessController; 38 import java.security.PrivilegedExceptionAction; 39 import java.security.PrivilegedActionException; 40 import java.util.Random; 41 42 43 /** 44 * A simple Pipe implementation based on a socket connection. 45 */ 46 47 class PipeImpl 48 extends Pipe 49 { 50 51 // Source and sink channels 52 private SourceChannel source; 53 private SinkChannel sink; 54 55 // Random object for handshake values 56 private static final Random rnd; 57 58 static { 59 Util.load(); 60 byte[] someBytes = new byte[8]; 61 boolean resultOK = IOUtil.randomBytes(someBytes); 62 if (resultOK) { 63 rnd = new Random(ByteBuffer.wrap(someBytes).getLong()); 64 } else { 65 rnd = new Random(); 66 } 67 } 68 69 private class Initializer 70 implements PrivilegedExceptionAction<Void> 71 { 72 73 private final SelectorProvider sp; 74 75 private IOException ioe = null; 76 77 private Initializer(SelectorProvider sp) { 78 this.sp = sp; 79 } 80 81 @Override 82 public Void run() throws IOException { 83 boolean interrupted = false; 84 85 ServerSocketChannel ssc = null; 86 SocketChannel sc1 = null; 87 SocketChannel sc2 = null; 88 89 try { 90 // loopback address 91 InetAddress lb = InetAddress.getByName("127.0.0.1"); 92 assert(lb.isLoopbackAddress()); 93 InetSocketAddress sa = null; 94 for(;;) { 95 // bind ServerSocketChannel to a port on the loopback 96 // address 97 if (ssc == null || !ssc.isOpen()) { 98 ssc = ServerSocketChannel.open(); 99 ssc.socket().bind(new InetSocketAddress(lb, 0)); 100 sa = new InetSocketAddress(lb, 101 ssc.socket().getLocalPort()); 102 } 103 104 // Establish connection (assume connections are eagerly 105 // accepted) 106 sc1 = SocketChannel.open(sa); 107 ByteBuffer bb = ByteBuffer.allocate(8); 108 long secret = rnd.nextLong(); 109 bb.putLong(secret).flip(); 110 sc1.write(bb); 111 112 // Get a connection and verify it is legitimate 113 sc2 = ssc.accept(); 114 bb.clear(); 115 sc2.read(bb); 116 bb.rewind(); 117 if (bb.getLong() == secret) 118 break; 119 sc2.close(); 120 sc1.close(); 121 } 122 123 // Create source and sink channels 124 source = new SourceChannelImpl(sp, sc1); 125 sink = new SinkChannelImpl(sp, sc2); 126 } catch (IOException e) { 127 try { 128 if (sc1 != null) 129 sc1.close(); 130 if (sc2 != null) 131 sc2.close(); 132 } catch (IOException e2) {} 133 134 if (!(e instanceof ClosedByInterruptException)) 135 throw new IOException("Unable to establish loopback" 136 + " connection", e); 137 interrupted = true; 138 Thread.interrupted(); 139 } finally { 140 try { 141 if (ssc != null) 142 ssc.close(); 143 } catch (IOException e2) {} 144 } 145 146 if (interrupted) 147 UninterruptibleConnect(); 148 149 return null; 150 } 151 152 // Use short-lived uninterruptible thread to establish 153 // loopback connections 154 private void UninterruptibleConnect() throws IOException { 155 Thread connector = new Thread("UninterruptibleConnector") { 156 ServerSocketChannel ssc = null; 157 SocketChannel sc1 = null; 158 SocketChannel sc2 = null; 159 160 @Override 161 public void run() { 162 try { 163 // loopback address 164 InetAddress lb = InetAddress.getByName("127.0.0.1"); 165 assert(lb.isLoopbackAddress()); 166 InetSocketAddress sa = null; 167 168 for (;;) { 169 // bind ServerSocketChannel to a port on the 170 // loopback address 171 if (ssc == null || !ssc.isOpen()) { 172 ssc = ServerSocketChannel.open(); 173 ssc.socket().bind(new InetSocketAddress(lb, 0)); 174 sa = new InetSocketAddress(lb, 175 ssc.socket().getLocalPort()); 176 } 177 assert(sa != null); 178 179 // Establish connection (assumes connections are 180 // eagerly accepted) 181 sc1 = SocketChannel.open(sa); 182 ByteBuffer bb = ByteBuffer.allocate(8); 183 long secret = rnd.nextLong(); 184 bb.putLong(secret).flip(); 185 sc1.write(bb); 186 187 // Get a connection and verify it is legitimate 188 sc2 = ssc.accept(); 189 bb.clear(); 190 sc2.read(bb); 191 bb.rewind(); 192 if (bb.getLong() == secret) 193 break; 194 sc2.close(); 195 sc1.close(); 196 } 197 198 // Create source and sink channels 199 source = new SourceChannelImpl(sp, sc1); 200 sink = new SinkChannelImpl(sp, sc2); 201 } catch (IOException e) { 202 try { 203 if (sc1 != null) 204 sc1.close(); 205 if (sc2 != null) 206 sc2.close(); 207 } catch (IOException e2) {} 208 ioe = e; 209 } finally { 210 try { 211 if (ssc != null) 212 ssc.close(); 213 } catch (IOException e2) {} 214 } 215 } 216 217 @Override 218 public void interrupt() {} 219 }; 220 connector.start(); 221 for(;;) { 222 try { 223 connector.join(); 224 break; 225 } catch (InterruptedException ex) {} 226 } 227 228 Thread.currentThread().interrupt(); 229 230 if (ioe != null || source == null || sink == null) 231 throw new IOException("Unable to establish loopback connection", 232 ioe); 233 } 234 } 235 236 PipeImpl(final SelectorProvider sp) throws IOException { 237 try { 238 AccessController.doPrivileged(new Initializer(sp)); 239 } catch (PrivilegedActionException x) { 240 throw (IOException)x.getCause(); 241 } 242 } 243 244 245 public SourceChannel source() { 246 return source; 247 } 248 249 public SinkChannel sink() { 250 return sink; 251 } 252 253 }