0N/A/*
3261N/A * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.nio.ch;
0N/A
0N/Aimport java.lang.reflect.Constructor;
0N/Aimport java.io.FileDescriptor;
0N/Aimport java.io.IOException;
0N/Aimport java.net.InetAddress;
0N/Aimport java.net.InetSocketAddress;
0N/Aimport java.nio.channels.Channel;
0N/Aimport java.nio.channels.SocketChannel;
0N/Aimport java.nio.channels.ServerSocketChannel;
0N/Aimport java.nio.channels.DatagramChannel;
0N/Aimport java.nio.channels.spi.SelectorProvider;
0N/A
0N/Aclass InheritedChannel {
0N/A
0N/A // the "types" of socket returned by soType0
0N/A private static final int UNKNOWN = -1;
0N/A private static final int SOCK_STREAM = 1;
0N/A private static final int SOCK_DGRAM = 2;
0N/A
0N/A // oflag values when opening a file
0N/A private static final int O_RDONLY = 0;
0N/A private static final int O_WRONLY = 1;
0N/A private static final int O_RDWR = 2;
0N/A
0N/A /*
0N/A * In order to "detach" the standard streams we dup them to /dev/null.
0N/A * In order to reduce the possibility of an error at close time we
0N/A * open /dev/null early - that way we know we won't run out of file
0N/A * descriptors at close time. This makes the close operation a
0N/A * simple dup2 operation for each of the standard streams.
0N/A */
0N/A private static int devnull = -1;
0N/A
0N/A private static void detachIOStreams() {
0N/A try {
0N/A dup2(devnull, 0);
0N/A dup2(devnull, 1);
0N/A dup2(devnull, 2);
0N/A } catch (IOException ioe) {
0N/A // this shouldn't happen
0N/A throw new InternalError();
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Override the implCloseSelectableChannel for each channel type - this
0N/A * allows us to "detach" the standard streams after closing and ensures
0N/A * that the underlying socket really closes.
0N/A */
0N/A public static class InheritedSocketChannelImpl extends SocketChannelImpl {
0N/A
0N/A InheritedSocketChannelImpl(SelectorProvider sp,
0N/A FileDescriptor fd,
0N/A InetSocketAddress remote)
0N/A throws IOException
0N/A {
0N/A super(sp, fd, remote);
0N/A }
0N/A
0N/A protected void implCloseSelectableChannel() throws IOException {
0N/A super.implCloseSelectableChannel();
0N/A detachIOStreams();
0N/A }
0N/A }
0N/A
0N/A public static class InheritedServerSocketChannelImpl extends
0N/A ServerSocketChannelImpl {
0N/A
0N/A InheritedServerSocketChannelImpl(SelectorProvider sp,
0N/A FileDescriptor fd)
0N/A throws IOException
0N/A {
2736N/A super(sp, fd, true);
0N/A }
0N/A
0N/A protected void implCloseSelectableChannel() throws IOException {
0N/A super.implCloseSelectableChannel();
0N/A detachIOStreams();
0N/A }
0N/A
0N/A }
0N/A
0N/A public static class InheritedDatagramChannelImpl extends
0N/A DatagramChannelImpl {
0N/A
0N/A InheritedDatagramChannelImpl(SelectorProvider sp,
0N/A FileDescriptor fd)
0N/A throws IOException
0N/A {
0N/A super(sp, fd);
0N/A }
0N/A
0N/A protected void implCloseSelectableChannel() throws IOException {
0N/A super.implCloseSelectableChannel();
0N/A detachIOStreams();
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * If there's a SecurityManager then check for the appropriate
0N/A * RuntimePermission.
0N/A */
0N/A private static void checkAccess(Channel c) {
0N/A SecurityManager sm = System.getSecurityManager();
0N/A if (sm != null) {
0N/A sm.checkPermission(
0N/A new RuntimePermission("inheritedChannel")
0N/A );
0N/A }
0N/A }
0N/A
0N/A
0N/A /*
0N/A * If standard inherited channel is connected to a socket then return a Channel
0N/A * of the appropriate type based standard input.
0N/A */
0N/A private static Channel createChannel() throws IOException {
0N/A
0N/A // dup the file descriptor - we do this so that for two reasons :-
0N/A // 1. Avoids any timing issues with FileDescriptor.in being closed
0N/A // or redirected while we create the channel.
0N/A // 2. Allows streams based on file descriptor 0 to co-exist with
0N/A // the channel (closing one doesn't impact the other)
0N/A
0N/A int fdVal = dup(0);
0N/A
0N/A // Examine the file descriptor - if it's not a socket then we don't
0N/A // create a channel so we release the file descriptor.
0N/A
0N/A int st;
0N/A st = soType0(fdVal);
0N/A if (st != SOCK_STREAM && st != SOCK_DGRAM) {
0N/A close0(fdVal);
0N/A return null;
0N/A }
0N/A
0N/A
0N/A // Next we create a FileDescriptor for the dup'ed file descriptor
0N/A // Have to use reflection and also make assumption on how FD
0N/A // is implemented.
0N/A
0N/A Class paramTypes[] = { int.class };
0N/A Constructor ctr = Reflect.lookupConstructor("java.io.FileDescriptor",
0N/A paramTypes);
0N/A Object args[] = { new Integer(fdVal) };
0N/A FileDescriptor fd = (FileDescriptor)Reflect.invoke(ctr, args);
0N/A
0N/A
0N/A // Now create the channel. If the socket is a streams socket then
0N/A // we see if tthere is a peer (ie: connected). If so, then we
0N/A // create a SocketChannel, otherwise a ServerSocketChannel.
0N/A // If the socket is a datagram socket then create a DatagramChannel
0N/A
0N/A SelectorProvider provider = SelectorProvider.provider();
0N/A assert provider instanceof sun.nio.ch.SelectorProviderImpl;
0N/A
0N/A Channel c;
0N/A if (st == SOCK_STREAM) {
0N/A InetAddress ia = peerAddress0(fdVal);
0N/A if (ia == null) {
0N/A c = new InheritedServerSocketChannelImpl(provider, fd);
0N/A } else {
0N/A int port = peerPort0(fdVal);
0N/A assert port > 0;
0N/A InetSocketAddress isa = new InetSocketAddress(ia, port);
0N/A c = new InheritedSocketChannelImpl(provider, fd, isa);
0N/A }
0N/A } else {
0N/A c = new InheritedDatagramChannelImpl(provider, fd);
0N/A }
0N/A return c;
0N/A }
0N/A
0N/A private static boolean haveChannel = false;
0N/A private static Channel channel = null;
0N/A
0N/A /*
0N/A * Returns a Channel representing the inherited channel if the
0N/A * inherited channel is a stream connected to a network socket.
0N/A */
0N/A public static synchronized Channel getChannel() throws IOException {
0N/A if (devnull < 0) {
0N/A devnull = open0("/dev/null", O_RDWR);
0N/A }
0N/A
0N/A // If we don't have the channel try to create it
0N/A if (!haveChannel) {
0N/A channel = createChannel();
0N/A haveChannel = true;
0N/A }
0N/A
0N/A // if there is a channel then do the security check before
0N/A // returning it.
0N/A if (channel != null) {
0N/A checkAccess(channel);
0N/A }
0N/A return channel;
0N/A }
0N/A
0N/A
0N/A // -- Native methods --
0N/A
0N/A private static native int dup(int fd) throws IOException;
0N/A private static native void dup2(int fd, int fd2) throws IOException;
0N/A private static native int open0(String path, int oflag) throws IOException;
0N/A private static native void close0(int fd) throws IOException;
0N/A private static native int soType0(int fd);
0N/A private static native InetAddress peerAddress0(int fd);
0N/A private static native int peerPort0(int fd);
0N/A
0N/A static {
0N/A Util.load();
0N/A }
0N/A}