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