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 LoopbackConnector connector = new LoopbackConnector(); 84 connector.run(); 85 if (ioe instanceof ClosedByInterruptException) { 86 ioe = null; 87 Thread connThread = new Thread(connector) { 88 @Override 89 public void interrupt() {} 90 }; 91 connThread.start(); 92 for(;;) { 93 try { 94 connThread.join(); 95 break; 96 } catch (InterruptedException ex) {} 97 } 98 Thread.currentThread().interrupt(); 99 } 100 101 if (ioe != null || source == null || sink == null) 102 throw new IOException("Unable to establish loopback connection", 103 ioe); 104 105 return null; 106 } 107 108 private class LoopbackConnector implements Runnable { 109 110 @Override 111 public void run() { 112 ServerSocketChannel ssc = null; 113 SocketChannel sc1 = null; 114 SocketChannel sc2 = null; 115 116 try { 117 // Loopback address 118 InetAddress lb = InetAddress.getByName("127.0.0.1"); 119 assert(lb.isLoopbackAddress()); 120 InetSocketAddress sa = null; 121 for(;;) { 122 // Bind ServerSocketChannel to a port on the loopback 123 // address 124 if (ssc == null || !ssc.isOpen()) { 125 ssc = ServerSocketChannel.open(); 126 ssc.socket().bind(new InetSocketAddress(lb, 0)); 127 sa = new InetSocketAddress(lb, 128 ssc.socket().getLocalPort()); 129 } 130 131 // Establish connection (assume connections are eagerly 132 // accepted) 133 sc1 = SocketChannel.open(sa); 134 ByteBuffer bb = ByteBuffer.allocate(8); 135 long secret = rnd.nextLong(); 136 bb.putLong(secret).flip(); 137 sc1.write(bb); 138 139 // Get a connection and verify it is legitimate 140 sc2 = ssc.accept(); 141 bb.clear(); 142 sc2.read(bb); 143 bb.rewind(); 144 if (bb.getLong() == secret) 145 break; 146 sc2.close(); 147 sc1.close(); 148 } 149 150 // Create source and sink channels 151 source = new SourceChannelImpl(sp, sc1); 152 sink = new SinkChannelImpl(sp, sc2); 153 } catch (IOException e) { 154 try { 155 if (sc1 != null) 156 sc1.close(); 157 if (sc2 != null) 158 sc2.close(); 159 } catch (IOException e2) {} 160 ioe = e; 161 } finally { 162 try { 163 if (ssc != null) 164 ssc.close(); 165 } catch (IOException e2) {} 166 } 167 } 168 } 169 } 170 171 PipeImpl(final SelectorProvider sp) throws IOException { 172 try { 173 AccessController.doPrivileged(new Initializer(sp)); 174 } catch (PrivilegedActionException x) { 175 throw (IOException)x.getCause(); 176 } 177 } 178 179 public SourceChannel source() { 180 return source; 181 } 182 183 public SinkChannel sink() { 184 return sink; 185 } 186 187 }