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