1 /*
   2  * Copyright (c) 2003, 2020, 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 package sun.nio.ch;
  27 
  28 import java.lang.reflect.Constructor;
  29 import java.io.FileDescriptor;
  30 import java.io.IOException;
  31 import java.net.InetAddress;
  32 import java.net.Inet6Address;
  33 import java.net.InetSocketAddress;
  34 import java.net.ProtocolFamily;
  35 import java.nio.channels.Channel;
  36 import java.nio.channels.spi.SelectorProvider;
  37 import static java.net.StandardProtocolFamily.INET6;
  38 import static java.net.StandardProtocolFamily.INET;
  39 
  40 class InheritedChannel {
  41 
  42     // the "types" of socket returned by soType0
  43     private static final int UNKNOWN            = -1;
  44     private static final int SOCK_STREAM        = 1;
  45     private static final int SOCK_DGRAM         = 2;
  46 
  47     // socket address type
  48     private static final int AF_UNKNOWN         = -1;
  49     private static final int AF_INET            = 1;
  50     private static final int AF_INET6           = 2;
  51     private static final int AF_UNIX            = 3;
  52 
  53     // oflag values when opening a file
  54     private static final int O_RDONLY           = 0;
  55     private static final int O_WRONLY           = 1;
  56     private static final int O_RDWR             = 2;
  57 
  58     /*
  59      * In order to "detach" the standard streams we dup them to /dev/null.
  60      * In order to reduce the possibility of an error at close time we
  61      * open /dev/null early - that way we know we won't run out of file
  62      * descriptors at close time. This makes the close operation a
  63      * simple dup2 operation for each of the standard streams.
  64      */
  65     private static int devnull = -1;
  66 
  67     private static void detachIOStreams() {
  68         try {
  69             dup2(devnull, 0);
  70             dup2(devnull, 1);
  71             dup2(devnull, 2);
  72         } catch (IOException ioe) {
  73             // this shouldn't happen
  74             throw new InternalError(ioe);
  75         }
  76     }
  77 
  78     /*
  79      * Override the implCloseSelectableChannel for each channel type - this
  80      * allows us to "detach" the standard streams after closing and ensures
  81      * that the underlying socket really closes.
  82      */
  83     public static class InheritedSocketChannelImpl extends SocketChannelImpl {
  84 
  85         static ProtocolFamily family(InetSocketAddress isa) {
  86             return (isa.getAddress() instanceof Inet6Address) ? INET6 : INET;
  87         }
  88 
  89         InheritedSocketChannelImpl(SelectorProvider sp,
  90                                    FileDescriptor fd,
  91                                    InetSocketAddress remote)
  92             throws IOException
  93         {
  94             super(sp, family(remote), fd, remote);
  95         }
  96 
  97         protected void implCloseSelectableChannel() throws IOException {
  98             super.implCloseSelectableChannel();
  99             detachIOStreams();
 100         }
 101     }
 102 
 103     public static class InheritedUnixChannelImpl extends UnixDomainSocketChannelImpl {
 104 
 105         InheritedUnixChannelImpl(FileDescriptor fd)
 106             throws IOException
 107         {
 108             super(fd);
 109         }
 110 
 111         protected void implCloseSelectableChannel() throws IOException {
 112             super.implCloseChannel();
 113             detachIOStreams();
 114         }
 115     }
 116 
 117     public static class InheritedServerSocketChannelImpl extends
 118         ServerSocketChannelImpl {
 119 
 120         InheritedServerSocketChannelImpl(SelectorProvider sp,
 121                                          FileDescriptor fd)
 122             throws IOException
 123         {
 124             super(sp, fd, true);
 125         }
 126 
 127         protected void implCloseSelectableChannel() throws IOException {
 128             super.implCloseSelectableChannel();
 129             detachIOStreams();
 130         }
 131 
 132     }
 133 
 134     public static class InheritedDatagramChannelImpl extends
 135         DatagramChannelImpl {
 136 
 137         InheritedDatagramChannelImpl(SelectorProvider sp,
 138                                      FileDescriptor fd)
 139             throws IOException
 140         {
 141             super(sp, fd);
 142         }
 143 
 144         protected void implCloseSelectableChannel() throws IOException {
 145             super.implCloseSelectableChannel();
 146             detachIOStreams();
 147         }
 148     }
 149 
 150     /*
 151      * If there's a SecurityManager then check for the appropriate
 152      * RuntimePermission.
 153      */
 154     private static void checkAccess(Channel c) {
 155         SecurityManager sm = System.getSecurityManager();
 156         if (sm != null) {
 157             sm.checkPermission(
 158                 new RuntimePermission("inheritedChannel")
 159             );
 160         }
 161     }
 162 
 163 
 164     /*
 165      * If standard inherited channel is connected to a socket then return a Channel
 166      * of the appropriate type based standard input.
 167      */
 168     private static Channel createChannel() throws IOException {
 169 
 170         // dup the file descriptor - we do this so that for two reasons :-
 171         // 1. Avoids any timing issues with FileDescriptor.in being closed
 172         //    or redirected while we create the channel.
 173         // 2. Allows streams based on file descriptor 0 to co-exist with
 174         //    the channel (closing one doesn't impact the other)
 175 
 176         int fdVal = dup(0);
 177 
 178         // Examine the file descriptor - if it's not a socket then we don't
 179         // create a channel so we release the file descriptor.
 180 
 181         int st;
 182         st = soType0(fdVal);
 183         if (st != SOCK_STREAM && st != SOCK_DGRAM) {
 184             close0(fdVal);
 185             return null;
 186         }
 187 
 188         // Next we create a FileDescriptor for the dup'ed file descriptor
 189         // Have to use reflection and also make assumption on how FD
 190         // is implemented.
 191 
 192         Class<?> paramTypes[] = { int.class };
 193         Constructor<?> ctr = Reflect.lookupConstructor("java.io.FileDescriptor",
 194                                                        paramTypes);
 195         Object args[] = { Integer.valueOf(fdVal) };
 196         FileDescriptor fd = (FileDescriptor)Reflect.invoke(ctr, args);
 197 
 198 
 199         // Now create the channel. If the socket is a streams socket then
 200         // we see if tthere is a peer (ie: connected). If so, then we
 201         // create a SocketChannel, otherwise a ServerSocketChannel.
 202         // If the socket is a datagram socket then create a DatagramChannel
 203 
 204         SelectorProvider provider = SelectorProvider.provider();
 205         assert provider instanceof sun.nio.ch.SelectorProviderImpl;
 206 
 207         Channel c;
 208         if (st == SOCK_STREAM) {
 209             int family = addressFamily(fdVal);
 210             if (family == AF_UNKNOWN)
 211                 return null;
 212             if (family == AF_UNIX) {
 213                 if (isConnected(fdVal)) {
 214                     return new InheritedUnixChannelImpl(fd);
 215                 } else {
 216                     // listener. unsupported.
 217                     return null;
 218                 }
 219             }
 220             InetAddress ia = peerAddress0(fdVal);
 221             if (ia == null) {
 222                c = new InheritedServerSocketChannelImpl(provider, fd);
 223             } else {
 224                int port = peerPort0(fdVal);
 225                assert port > 0;
 226                InetSocketAddress isa = new InetSocketAddress(ia, port);
 227                c = new InheritedSocketChannelImpl(provider, fd, isa);
 228             }
 229         } else {
 230             c = new InheritedDatagramChannelImpl(provider, fd);
 231         }
 232         return c;
 233     }
 234 
 235     private static boolean haveChannel = false;
 236     private static Channel channel = null;
 237 
 238     /*
 239      * Returns a Channel representing the inherited channel if the
 240      * inherited channel is a stream connected to a network socket.
 241      */
 242     public static synchronized Channel getChannel() throws IOException {
 243         if (devnull < 0) {
 244             devnull = open0("/dev/null", O_RDWR);
 245         }
 246 
 247         // If we don't have the channel try to create it
 248         if (!haveChannel) {
 249             channel = createChannel();
 250             haveChannel = true;
 251         }
 252 
 253         // if there is a channel then do the security check before
 254         // returning it.
 255         if (channel != null) {
 256             checkAccess(channel);
 257         }
 258         return channel;
 259     }
 260 
 261 
 262     // -- Native methods --
 263 
 264     private static native void initIDs();
 265     private static native int dup(int fd) throws IOException;
 266     private static native void dup2(int fd, int fd2) throws IOException;
 267     private static native int open0(String path, int oflag) throws IOException;
 268     private static native void close0(int fd) throws IOException;
 269     private static native int soType0(int fd);
 270     private static native int addressFamily(int fd);
 271     private static native InetAddress peerAddress0(int fd);
 272     private static native int peerPort0(int fd);
 273 
 274     // return true if socket is connected to a peer
 275     private static native boolean isConnected(int fd);
 276 
 277     static {
 278         IOUtil.load();
 279         initIDs();
 280     }
 281 }