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 }