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