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 }