Path: blob/master/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java
41137 views
/*1* Copyright (c) 2003, 2021, 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*/2425package sun.nio.ch;2627import java.lang.reflect.Constructor;28import java.io.FileDescriptor;29import java.io.IOException;30import java.net.InetAddress;31import java.net.Inet6Address;32import java.net.InetSocketAddress;33import java.net.ProtocolFamily;34import java.net.SocketAddress;35import java.net.UnixDomainSocketAddress;36import java.nio.channels.Channel;37import java.nio.channels.spi.SelectorProvider;38import static java.net.StandardProtocolFamily.INET6;39import static java.net.StandardProtocolFamily.INET;40import static java.net.StandardProtocolFamily.UNIX;4142class InheritedChannel {4344// the "types" of socket returned by soType045private static final int UNKNOWN = -1;46private static final int SOCK_STREAM = 1;47private static final int SOCK_DGRAM = 2;4849// socket address type50static final int AF_UNKNOWN = -1;51static final int AF_INET = 1;52static final int AF_INET6 = 2;53static final int AF_UNIX = 3;5455// oflag values when opening a file56private static final int O_RDONLY = 0;57private static final int O_WRONLY = 1;58private static final int O_RDWR = 2;5960/*61* In order to "detach" the standard streams we dup them to /dev/null.62* In order to reduce the possibility of an error at close time we63* open /dev/null early - that way we know we won't run out of file64* descriptors at close time. This makes the close operation a65* simple dup2 operation for each of the standard streams.66*/67private static int devnull = -1;6869private static void detachIOStreams() {70try {71dup2(devnull, 0);72dup2(devnull, 1);73dup2(devnull, 2);74} catch (IOException ioe) {75// this shouldn't happen76throw new InternalError(ioe);77}78}7980static ProtocolFamily protocolFamily(SocketAddress sa) {81if (sa instanceof UnixDomainSocketAddress) {82return UNIX;83} else {84InetSocketAddress isa = (InetSocketAddress) sa;85return (isa.getAddress() instanceof Inet6Address) ? INET6 : INET;86}87}8889static ProtocolFamily protocolFamily(int family) {90return switch (family) {91case AF_INET -> INET;92case AF_INET6 -> INET6;93case AF_UNIX -> UNIX;94default -> throw new IllegalArgumentException();95};96}9798/*99* Override the implCloseSelectableChannel for each channel type - this100* allows us to "detach" the standard streams after closing and ensures101* that the underlying socket really closes.102*/103public static class InheritedSocketChannelImpl extends SocketChannelImpl {104105InheritedSocketChannelImpl(SelectorProvider sp,106FileDescriptor fd,107SocketAddress remote)108throws IOException109{110super(sp, protocolFamily(remote), fd, remote);111}112113protected void implCloseSelectableChannel() throws IOException {114super.implCloseSelectableChannel();115detachIOStreams();116}117}118119public static class InheritedServerSocketChannelImpl extends ServerSocketChannelImpl {120121InheritedServerSocketChannelImpl(SelectorProvider sp,122ProtocolFamily family,123FileDescriptor fd)124throws IOException125{126super(sp, family, fd, true);127}128129@Override130protected void implCloseSelectableChannel() throws IOException {131super.implCloseSelectableChannel();132detachIOStreams();133}134}135136public static class InheritedDatagramChannelImpl extends DatagramChannelImpl {137138InheritedDatagramChannelImpl(SelectorProvider sp,139FileDescriptor fd)140throws IOException141{142super(sp, fd);143}144145protected void implCloseSelectableChannel() throws IOException {146super.implCloseSelectableChannel();147detachIOStreams();148}149}150151/*152* If there's a SecurityManager then check for the appropriate153* RuntimePermission.154*/155private static void checkAccess() {156@SuppressWarnings("removal")157SecurityManager sm = System.getSecurityManager();158if (sm != null) {159sm.checkPermission(new RuntimePermission("inheritedChannel"));160}161}162163/*164* If standard inherited channel is connected to a socket then return a Channel165* of the appropriate type based standard input.166*/167private static Channel createChannel() throws IOException {168169// dup the file descriptor - we do this so that for two reasons :-170// 1. Avoids any timing issues with FileDescriptor.in being closed171// or redirected while we create the channel.172// 2. Allows streams based on file descriptor 0 to co-exist with173// the channel (closing one doesn't impact the other)174175int fdVal = dup(0);176177// Examine the file descriptor - if it's not a socket then we don't178// create a channel so we release the file descriptor.179180int st;181st = soType0(fdVal);182if (st != SOCK_STREAM && st != SOCK_DGRAM) {183close0(fdVal);184return null;185}186187// Next we create a FileDescriptor for the dup'ed file descriptor188// Have to use reflection and also make assumption on how FD189// is implemented.190191Class<?> paramTypes[] = { int.class };192Constructor<?> ctr = Reflect.lookupConstructor("java.io.FileDescriptor",193paramTypes);194Object args[] = { Integer.valueOf(fdVal) };195FileDescriptor fd = (FileDescriptor)Reflect.invoke(ctr, args);196197198// Now create the channel. If the socket is a streams socket then199// we see if there is a peer (ie: connected). If so, then we200// create a SocketChannel, otherwise a ServerSocketChannel.201// If the socket is a datagram socket then create a DatagramChannel202203SelectorProvider provider = SelectorProvider.provider();204assert provider instanceof sun.nio.ch.SelectorProviderImpl;205206Channel c;207if (st == SOCK_STREAM) {208int family = addressFamily(fdVal);209if (family == AF_UNKNOWN)210return null;211ProtocolFamily pfamily = protocolFamily(family);212if (family == AF_UNIX) {213if (isConnected(fdVal)) {214var sa = UnixDomainSocketAddress.of(unixPeerAddress(fdVal));215return new InheritedSocketChannelImpl(provider, fd, sa);216} else {217return new InheritedServerSocketChannelImpl(provider, pfamily, fd);218}219}220InetAddress ia = inetPeerAddress0(fdVal);221if (ia == null) {222c = new InheritedServerSocketChannelImpl(provider, pfamily, fd);223} else {224int port = peerPort0(fdVal);225226assert port > 0;227InetSocketAddress isa = new InetSocketAddress(ia, port);228c = new InheritedSocketChannelImpl(provider, fd, isa);229}230} else {231c = new InheritedDatagramChannelImpl(provider, fd);232}233return c;234}235236private static boolean haveChannel = false;237private static Channel channel = null;238239/*240* Returns a Channel representing the inherited channel if the241* inherited channel is a stream connected to a network socket.242*/243public static synchronized Channel getChannel() throws IOException {244if (devnull < 0) {245devnull = open0("/dev/null", O_RDWR);246}247248// If we don't have the channel try to create it249if (!haveChannel) {250channel = createChannel();251haveChannel = true;252}253254// if there is a channel then do the security check before255// returning it.256if (channel != null) {257checkAccess();258}259return channel;260}261262private static String unixPeerAddress(int fd) throws IOException {263byte[] bytes = unixPeerAddress0(fd);264return new String(bytes);265}266267// -- Native methods --268269private static native void initIDs();270private static native int dup(int fd) throws IOException;271private static native void dup2(int fd, int fd2) throws IOException;272private static native int open0(String path, int oflag) throws IOException;273private static native void close0(int fd) throws IOException;274private static native int soType0(int fd);275private static native int addressFamily(int fd);276private static native InetAddress inetPeerAddress0(int fd);277private static native byte[] unixPeerAddress0(int fd);278private static native int peerPort0(int fd);279280// return true if socket is connected to a peer281private static native boolean isConnected(int fd);282283static {284IOUtil.load();285initIDs();286}287}288289290