1/* 2 * Copyright (c) 2002, 2016, 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 29package sun.nio.ch; 30 31import java.io.IOException; 32import java.net.InetAddress; 33import java.net.InetSocketAddress; 34import java.nio.*; 35import java.nio.channels.*; 36import java.nio.channels.spi.*; 37import java.security.AccessController; 38import java.security.PrivilegedExceptionAction; 39import java.security.PrivilegedActionException; 40import java.security.SecureRandom; 41import java.util.Random; 42 43 44/** 45 * A simple Pipe implementation based on a socket connection. 46 */ 47 48class PipeImpl 49 extends Pipe 50{ 51 // Number of bytes in the secret handshake. 52 private static final int NUM_SECRET_BYTES = 16; 53 54 // Random object for handshake values 55 private static final Random RANDOM_NUMBER_GENERATOR = new SecureRandom(); 56 57 // Source and sink channels 58 private SourceChannel source; 59 private SinkChannel sink; 60 61 private class Initializer 62 implements PrivilegedExceptionAction<Void> 63 { 64 65 private final SelectorProvider sp; 66 67 private IOException ioe = null; 68 69 private Initializer(SelectorProvider sp) { 70 this.sp = sp; 71 } 72 73 @Override 74 public Void run() throws IOException { 75 LoopbackConnector connector = new LoopbackConnector(); 76 connector.run(); 77 if (ioe instanceof ClosedByInterruptException) { 78 ioe = null; 79 Thread connThread = new Thread(connector) { 80 @Override 81 public void interrupt() {} 82 }; 83 connThread.start(); 84 for (;;) { 85 try { 86 connThread.join(); 87 break; 88 } catch (InterruptedException ex) {} 89 } 90 Thread.currentThread().interrupt(); 91 } 92 93 if (ioe != null) 94 throw new IOException("Unable to establish loopback connection", ioe); 95 96 return null; 97 } 98 99 private class LoopbackConnector implements Runnable { 100 101 @Override 102 public void run() { 103 ServerSocketChannel ssc = null; 104 SocketChannel sc1 = null; 105 SocketChannel sc2 = null; 106 107 try { 108 // Create secret with a backing array. 109 ByteBuffer secret = ByteBuffer.allocate(NUM_SECRET_BYTES); 110 ByteBuffer bb = ByteBuffer.allocate(NUM_SECRET_BYTES); 111 112 // Loopback address 113 InetAddress lb = InetAddress.getByName("127.0.0.1"); 114 assert(lb.isLoopbackAddress()); 115 InetSocketAddress sa = null; 116 for(;;) { 117 // Bind ServerSocketChannel to a port on the loopback 118 // address 119 if (ssc == null || !ssc.isOpen()) { 120 ssc = ServerSocketChannel.open(); 121 ssc.socket().bind(new InetSocketAddress(lb, 0)); 122 sa = new InetSocketAddress(lb, ssc.socket().getLocalPort()); 123 } 124 125 // Establish connection (assume connections are eagerly 126 // accepted) 127 sc1 = SocketChannel.open(sa); 128 RANDOM_NUMBER_GENERATOR.nextBytes(secret.array()); 129 do { 130 sc1.write(secret); 131 } while (secret.hasRemaining()); 132 secret.rewind(); 133 134 // Get a connection and verify it is legitimate 135 sc2 = ssc.accept(); 136 do { 137 sc2.read(bb); 138 } while (bb.hasRemaining()); 139 bb.rewind(); 140 141 if (bb.equals(secret)) 142 break; 143 144 sc2.close(); 145 sc1.close(); 146 } 147 148 // Create source and sink channels 149 source = new SourceChannelImpl(sp, sc1); 150 sink = new SinkChannelImpl(sp, sc2); 151 } catch (IOException e) { 152 try { 153 if (sc1 != null) 154 sc1.close(); 155 if (sc2 != null) 156 sc2.close(); 157 } catch (IOException e2) {} 158 ioe = e; 159 } finally { 160 try { 161 if (ssc != null) 162 ssc.close(); 163 } catch (IOException e2) {} 164 } 165 } 166 } 167 } 168 169 PipeImpl(final SelectorProvider sp) throws IOException { 170 try { 171 AccessController.doPrivileged(new Initializer(sp)); 172 } catch (PrivilegedActionException x) { 173 throw (IOException)x.getCause(); 174 } 175 } 176 177 public SourceChannel source() { 178 return source; 179 } 180 181 public SinkChannel sink() { 182 return sink; 183 } 184 185} 186