1 /* 2 * Copyright (c) 2003, 2021, 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.net.SocketAddress; 36 import java.net.UnixDomainSocketAddress; 37 import java.nio.channels.Channel; 38 import java.nio.channels.spi.SelectorProvider; 39 import static java.net.StandardProtocolFamily.INET6; 40 import static java.net.StandardProtocolFamily.INET; 41 import static java.net.StandardProtocolFamily.UNIX; 42 43 class InheritedChannel { 44 45 // the "types" of socket returned by soType0 46 private static final int UNKNOWN = -1; 47 private static final int SOCK_STREAM = 1; 48 private static final int SOCK_DGRAM = 2; 49 50 // socket address type 51 static final int AF_UNKNOWN = -1; 52 static final int AF_INET = 1; 53 static final int AF_INET6 = 2; 54 static final int AF_UNIX = 3; 55 56 // oflag values when opening a file 57 private static final int O_RDONLY = 0; 58 private static final int O_WRONLY = 1; 59 private static final int O_RDWR = 2; 60 61 /* 62 * In order to "detach" the standard streams we dup them to /dev/null. 63 * In order to reduce the possibility of an error at close time we 64 * open /dev/null early - that way we know we won't run out of file 65 * descriptors at close time. This makes the close operation a 66 * simple dup2 operation for each of the standard streams. 67 */ 68 private static int devnull = -1; 69 detachIOStreams()70 private static void detachIOStreams() { 71 try { 72 dup2(devnull, 0); 73 dup2(devnull, 1); 74 dup2(devnull, 2); 75 } catch (IOException ioe) { 76 // this shouldn't happen 77 throw new InternalError(ioe); 78 } 79 } 80 protocolFamily(SocketAddress sa)81 static ProtocolFamily protocolFamily(SocketAddress sa) { 82 if (sa instanceof UnixDomainSocketAddress) { 83 return UNIX; 84 } else { 85 InetSocketAddress isa = (InetSocketAddress) sa; 86 return (isa.getAddress() instanceof Inet6Address) ? INET6 : INET; 87 } 88 } 89 protocolFamily(int family)90 static ProtocolFamily protocolFamily(int family) { 91 return switch (family) { 92 case AF_INET -> INET; 93 case AF_INET6 -> INET6; 94 case AF_UNIX -> UNIX; 95 default -> throw new IllegalArgumentException(); 96 }; 97 } 98 99 /* 100 * Override the implCloseSelectableChannel for each channel type - this 101 * allows us to "detach" the standard streams after closing and ensures 102 * that the underlying socket really closes. 103 */ 104 public static class InheritedSocketChannelImpl extends SocketChannelImpl { 105 InheritedSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, SocketAddress remote)106 InheritedSocketChannelImpl(SelectorProvider sp, 107 FileDescriptor fd, 108 SocketAddress remote) 109 throws IOException 110 { 111 super(sp, protocolFamily(remote), fd, remote); 112 } 113 implCloseSelectableChannel()114 protected void implCloseSelectableChannel() throws IOException { 115 super.implCloseSelectableChannel(); 116 detachIOStreams(); 117 } 118 } 119 120 public static class InheritedServerSocketChannelImpl extends ServerSocketChannelImpl { 121 InheritedServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family, FileDescriptor fd)122 InheritedServerSocketChannelImpl(SelectorProvider sp, 123 ProtocolFamily family, 124 FileDescriptor fd) 125 throws IOException 126 { 127 super(sp, family, fd, true); 128 } 129 130 @Override implCloseSelectableChannel()131 protected void implCloseSelectableChannel() throws IOException { 132 super.implCloseSelectableChannel(); 133 detachIOStreams(); 134 } 135 } 136 137 public static class InheritedDatagramChannelImpl extends DatagramChannelImpl { 138 InheritedDatagramChannelImpl(SelectorProvider sp, FileDescriptor fd)139 InheritedDatagramChannelImpl(SelectorProvider sp, 140 FileDescriptor fd) 141 throws IOException 142 { 143 super(sp, fd); 144 } 145 implCloseSelectableChannel()146 protected void implCloseSelectableChannel() throws IOException { 147 super.implCloseSelectableChannel(); 148 detachIOStreams(); 149 } 150 } 151 152 /* 153 * If there's a SecurityManager then check for the appropriate 154 * RuntimePermission. 155 */ checkAccess()156 private static void checkAccess() { 157 @SuppressWarnings("removal") 158 SecurityManager sm = System.getSecurityManager(); 159 if (sm != null) { 160 sm.checkPermission(new RuntimePermission("inheritedChannel")); 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 */ createChannel()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 there 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 ProtocolFamily pfamily = protocolFamily(family); 213 if (family == AF_UNIX) { 214 if (isConnected(fdVal)) { 215 var sa = UnixDomainSocketAddress.of(unixPeerAddress(fdVal)); 216 return new InheritedSocketChannelImpl(provider, fd, sa); 217 } else { 218 return new InheritedServerSocketChannelImpl(provider, pfamily, fd); 219 } 220 } 221 InetAddress ia = inetPeerAddress0(fdVal); 222 if (ia == null) { 223 c = new InheritedServerSocketChannelImpl(provider, pfamily, fd); 224 } else { 225 int port = peerPort0(fdVal); 226 227 assert port > 0; 228 InetSocketAddress isa = new InetSocketAddress(ia, port); 229 c = new InheritedSocketChannelImpl(provider, fd, isa); 230 } 231 } else { 232 c = new InheritedDatagramChannelImpl(provider, fd); 233 } 234 return c; 235 } 236 237 private static boolean haveChannel = false; 238 private static Channel channel = null; 239 240 /* 241 * Returns a Channel representing the inherited channel if the 242 * inherited channel is a stream connected to a network socket. 243 */ getChannel()244 public static synchronized Channel getChannel() throws IOException { 245 if (devnull < 0) { 246 devnull = open0("/dev/null", O_RDWR); 247 } 248 249 // If we don't have the channel try to create it 250 if (!haveChannel) { 251 channel = createChannel(); 252 haveChannel = true; 253 } 254 255 // if there is a channel then do the security check before 256 // returning it. 257 if (channel != null) { 258 checkAccess(); 259 } 260 return channel; 261 } 262 unixPeerAddress(int fd)263 private static String unixPeerAddress(int fd) throws IOException { 264 byte[] bytes = unixPeerAddress0(fd); 265 return new String(bytes); 266 } 267 268 // -- Native methods -- 269 initIDs()270 private static native void initIDs(); dup(int fd)271 private static native int dup(int fd) throws IOException; dup2(int fd, int fd2)272 private static native void dup2(int fd, int fd2) throws IOException; open0(String path, int oflag)273 private static native int open0(String path, int oflag) throws IOException; close0(int fd)274 private static native void close0(int fd) throws IOException; soType0(int fd)275 private static native int soType0(int fd); addressFamily(int fd)276 private static native int addressFamily(int fd); inetPeerAddress0(int fd)277 private static native InetAddress inetPeerAddress0(int fd); unixPeerAddress0(int fd)278 private static native byte[] unixPeerAddress0(int fd); peerPort0(int fd)279 private static native int peerPort0(int fd); 280 281 // return true if socket is connected to a peer isConnected(int fd)282 private static native boolean isConnected(int fd); 283 284 static { IOUtil.load()285 IOUtil.load(); initIDs()286 initIDs(); 287 } 288 } 289