blob: ccf67cae397ac0383aaa41373d5b7c8380345173 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
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
26package sun.nio.ch;
27
28import java.lang.reflect.Constructor;
29import java.io.FileDescriptor;
30import java.io.IOException;
31import java.net.InetAddress;
32import java.net.InetSocketAddress;
33import java.nio.channels.Channel;
34import java.nio.channels.SocketChannel;
35import java.nio.channels.ServerSocketChannel;
36import java.nio.channels.DatagramChannel;
37import java.nio.channels.spi.SelectorProvider;
38
39class 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}