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