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 }