jdk/src/solaris/classes/sun/nio/ch/InheritedChannel.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2003-2004 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any 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 
       
    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 
       
    78         InheritedSocketChannelImpl(SelectorProvider sp,
       
    79                                    FileDescriptor fd,
       
    80                                    InetSocketAddress remote)
       
    81             throws IOException
       
    82         {
       
    83             super(sp, fd, remote);
       
    84         }
       
    85 
       
    86         protected void implCloseSelectableChannel() throws IOException {
       
    87             super.implCloseSelectableChannel();
       
    88             detachIOStreams();
       
    89         }
       
    90     }
       
    91 
       
    92     public static class InheritedServerSocketChannelImpl extends
       
    93         ServerSocketChannelImpl {
       
    94 
       
    95         InheritedServerSocketChannelImpl(SelectorProvider sp,
       
    96                                          FileDescriptor fd)
       
    97             throws IOException
       
    98         {
       
    99             super(sp, fd);
       
   100         }
       
   101 
       
   102         protected void implCloseSelectableChannel() throws IOException {
       
   103             super.implCloseSelectableChannel();
       
   104             detachIOStreams();
       
   105         }
       
   106 
       
   107     }
       
   108 
       
   109     public static class InheritedDatagramChannelImpl extends
       
   110         DatagramChannelImpl {
       
   111 
       
   112         InheritedDatagramChannelImpl(SelectorProvider sp,
       
   113                                      FileDescriptor fd)
       
   114             throws IOException
       
   115         {
       
   116             super(sp, fd);
       
   117         }
       
   118 
       
   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      */
       
   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      */
       
   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      */
       
   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 
       
   229     private static native int dup(int fd) throws IOException;
       
   230     private static native void dup2(int fd, int fd2) throws IOException;
       
   231     private static native int open0(String path, int oflag) throws IOException;
       
   232     private static native void close0(int fd) throws IOException;
       
   233     private static native int soType0(int fd);
       
   234     private static native InetAddress peerAddress0(int fd);
       
   235     private static native int peerPort0(int fd);
       
   236 
       
   237     static {
       
   238         Util.load();
       
   239     }
       
   240 }