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