Path: blob/master/src/java.base/windows/classes/sun/nio/ch/PipeImpl.java
67773 views
/*1* Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26*/2728package sun.nio.ch;2930import java.io.IOException;31import java.net.InetAddress;32import java.net.InetSocketAddress;33import java.net.SocketAddress;34import java.net.StandardSocketOptions;35import java.net.UnixDomainSocketAddress;36import java.nio.*;37import java.nio.channels.*;38import java.nio.file.Files;39import java.nio.file.Path;40import java.nio.channels.spi.*;41import java.security.AccessController;42import java.security.PrivilegedExceptionAction;43import java.security.PrivilegedActionException;44import java.security.SecureRandom;45import java.util.Random;4647import static java.net.StandardProtocolFamily.UNIX;4849/**50* A simple Pipe implementation based on a socket connection.51*/5253class PipeImpl54extends Pipe55{56// Number of bytes in the secret handshake.57private static final int NUM_SECRET_BYTES = 16;5859// Random object for handshake values60private static final Random RANDOM_NUMBER_GENERATOR = new SecureRandom();6162// Source and sink channels63private final SourceChannelImpl source;64private final SinkChannelImpl sink;6566private static class Initializer67implements PrivilegedExceptionAction<Void>68{6970private final SelectorProvider sp;71private final boolean preferUnixDomain;72private IOException ioe;73SourceChannelImpl source;74SinkChannelImpl sink;7576private Initializer(SelectorProvider sp, boolean preferUnixDomain) {77this.sp = sp;78this.preferUnixDomain = preferUnixDomain;79}8081@Override82public Void run() throws IOException {83LoopbackConnector connector = new LoopbackConnector();84connector.run();85if (ioe instanceof ClosedByInterruptException) {86ioe = null;87Thread connThread = new Thread(connector) {88@Override89public void interrupt() {}90};91connThread.start();92for (;;) {93try {94connThread.join();95break;96} catch (InterruptedException ex) {}97}98Thread.currentThread().interrupt();99}100101if (ioe != null)102throw new IOException("Unable to establish loopback connection", ioe);103104return null;105}106107private class LoopbackConnector implements Runnable {108109@Override110public void run() {111ServerSocketChannel ssc = null;112SocketChannel sc1 = null;113SocketChannel sc2 = null;114// Loopback address115SocketAddress sa = null;116117try {118// Create secret with a backing array.119ByteBuffer secret = ByteBuffer.allocate(NUM_SECRET_BYTES);120ByteBuffer bb = ByteBuffer.allocate(NUM_SECRET_BYTES);121122for(;;) {123// Bind ServerSocketChannel to a port on the loopback124// address125if (ssc == null || !ssc.isOpen()) {126ssc = createListener(preferUnixDomain);127sa = ssc.getLocalAddress();128}129130// Establish connection (assume connections are eagerly131// accepted)132sc1 = SocketChannel.open(sa);133RANDOM_NUMBER_GENERATOR.nextBytes(secret.array());134do {135sc1.write(secret);136} while (secret.hasRemaining());137secret.rewind();138139// Get a connection and verify it is legitimate140sc2 = ssc.accept();141do {142sc2.read(bb);143} while (bb.hasRemaining());144bb.rewind();145146if (bb.equals(secret))147break;148149sc2.close();150sc1.close();151}152153// Create source and sink channels154source = new SourceChannelImpl(sp, sc1);155sink = new SinkChannelImpl(sp, sc2);156} catch (IOException e) {157try {158if (sc1 != null)159sc1.close();160if (sc2 != null)161sc2.close();162} catch (IOException e2) {}163ioe = e;164} finally {165try {166if (ssc != null)167ssc.close();168if (sa instanceof UnixDomainSocketAddress uaddr) {169Files.deleteIfExists(uaddr.getPath());170}171} catch (IOException e2) {}172}173}174}175}176177/**178* Creates a (TCP) Pipe implementation that supports buffering.179*/180PipeImpl(SelectorProvider sp) throws IOException {181this(sp, true, false);182}183184/**185* Creates Pipe implementation that supports optionally buffering186* and is TCP by default, but if Unix domain is supported and187* preferAfUnix is true, then Unix domain sockets are used.188*189* @param preferAfUnix use Unix domain sockets if supported190*191* @param buffering if false set TCP_NODELAY on TCP sockets192*/193@SuppressWarnings("removal")194PipeImpl(SelectorProvider sp, boolean preferAfUnix, boolean buffering) throws IOException {195Initializer initializer = new Initializer(sp, preferAfUnix);196try {197AccessController.doPrivileged(initializer);198SinkChannelImpl sink = initializer.sink;199if (sink.isNetSocket() && !buffering) {200sink.setOption(StandardSocketOptions.TCP_NODELAY, true);201}202} catch (PrivilegedActionException pae) {203throw (IOException) pae.getCause();204}205this.source = initializer.source;206this.sink = initializer.sink;207}208209public SourceChannelImpl source() {210return source;211}212213public SinkChannelImpl sink() {214return sink;215}216217private static ServerSocketChannel createListener(boolean preferUnixDomain) throws IOException {218ServerSocketChannel listener = null;219if (preferUnixDomain && UnixDomainSockets.isSupported()) {220try {221listener = ServerSocketChannel.open(UNIX);222listener.bind(null);223return listener;224} catch (IOException | UnsupportedOperationException e) {225if (listener != null)226listener.close();227}228}229listener = ServerSocketChannel.open();230InetAddress lb = InetAddress.getLoopbackAddress();231listener.bind(new InetSocketAddress(lb, 0));232return listener;233}234}235236237