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