001: /*
002: * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.nio.ch;
027:
028: import java.lang.reflect.Constructor;
029: import java.io.FileDescriptor;
030: import java.io.IOException;
031: import java.net.InetAddress;
032: import java.net.InetSocketAddress;
033: import java.nio.channels.Channel;
034: import java.nio.channels.SocketChannel;
035: import java.nio.channels.ServerSocketChannel;
036: import java.nio.channels.DatagramChannel;
037: import java.nio.channels.spi.SelectorProvider;
038:
039: class InheritedChannel {
040:
041: // the "types" of socket returned by soType0
042: private static final int UNKNOWN = -1;
043: private static final int SOCK_STREAM = 1;
044: private static final int SOCK_DGRAM = 2;
045:
046: // oflag values when opening a file
047: private static final int O_RDONLY = 0;
048: private static final int O_WRONLY = 1;
049: private static final int O_RDWR = 2;
050:
051: /*
052: * In order to "detach" the standard streams we dup them to /dev/null.
053: * In order to reduce the possibility of an error at close time we
054: * open /dev/null early - that way we know we won't run out of file
055: * descriptors at close time. This makes the close operation a
056: * simple dup2 operation for each of the standard streams.
057: */
058: private static int devnull = -1;
059:
060: private static void detachIOStreams() {
061: try {
062: dup2(devnull, 0);
063: dup2(devnull, 1);
064: dup2(devnull, 2);
065: } catch (IOException ioe) {
066: // this shouldn't happen
067: throw new InternalError();
068: }
069: }
070:
071: /*
072: * Override the implCloseSelectableChannel for each channel type - this
073: * allows us to "detach" the standard streams after closing and ensures
074: * that the underlying socket really closes.
075: */
076: public static class InheritedSocketChannelImpl extends
077: SocketChannelImpl {
078:
079: InheritedSocketChannelImpl(SelectorProvider sp,
080: FileDescriptor fd, InetSocketAddress remote)
081: throws IOException {
082: super (sp, fd, remote);
083: }
084:
085: protected void implCloseSelectableChannel() throws IOException {
086: super .implCloseSelectableChannel();
087: detachIOStreams();
088: }
089: }
090:
091: public static class InheritedServerSocketChannelImpl extends
092: ServerSocketChannelImpl {
093:
094: InheritedServerSocketChannelImpl(SelectorProvider sp,
095: FileDescriptor fd) throws IOException {
096: super (sp, fd);
097: }
098:
099: protected void implCloseSelectableChannel() throws IOException {
100: super .implCloseSelectableChannel();
101: detachIOStreams();
102: }
103:
104: }
105:
106: public static class InheritedDatagramChannelImpl extends
107: DatagramChannelImpl {
108:
109: InheritedDatagramChannelImpl(SelectorProvider sp,
110: FileDescriptor fd) throws IOException {
111: super (sp, fd);
112: }
113:
114: protected void implCloseSelectableChannel() throws IOException {
115: super .implCloseSelectableChannel();
116: detachIOStreams();
117: }
118: }
119:
120: /*
121: * If there's a SecurityManager then check for the appropriate
122: * RuntimePermission.
123: */
124: private static void checkAccess(Channel c) {
125: SecurityManager sm = System.getSecurityManager();
126: if (sm != null) {
127: sm
128: .checkPermission(new RuntimePermission(
129: "inheritedChannel"));
130: }
131: }
132:
133: /*
134: * If standard inherited channel is connected to a socket then return a Channel
135: * of the appropriate type based standard input.
136: */
137: private static Channel createChannel() throws IOException {
138:
139: // dup the file descriptor - we do this so that for two reasons :-
140: // 1. Avoids any timing issues with FileDescriptor.in being closed
141: // or redirected while we create the channel.
142: // 2. Allows streams based on file descriptor 0 to co-exist with
143: // the channel (closing one doesn't impact the other)
144:
145: int fdVal = dup(0);
146:
147: // Examine the file descriptor - if it's not a socket then we don't
148: // create a channel so we release the file descriptor.
149:
150: int st;
151: st = soType0(fdVal);
152: if (st != SOCK_STREAM && st != SOCK_DGRAM) {
153: close0(fdVal);
154: return null;
155: }
156:
157: // Next we create a FileDescriptor for the dup'ed file descriptor
158: // Have to use reflection and also make assumption on how FD
159: // is implemented.
160:
161: Class paramTypes[] = { int.class };
162: Constructor ctr = Reflect.lookupConstructor(
163: "java.io.FileDescriptor", paramTypes);
164: Object args[] = { new Integer(fdVal) };
165: FileDescriptor fd = (FileDescriptor) Reflect.invoke(ctr, args);
166:
167: // Now create the channel. If the socket is a streams socket then
168: // we see if tthere is a peer (ie: connected). If so, then we
169: // create a SocketChannel, otherwise a ServerSocketChannel.
170: // If the socket is a datagram socket then create a DatagramChannel
171:
172: SelectorProvider provider = SelectorProvider.provider();
173: assert provider instanceof sun.nio.ch.SelectorProviderImpl;
174:
175: Channel c;
176: if (st == SOCK_STREAM) {
177: InetAddress ia = peerAddress0(fdVal);
178: if (ia == null) {
179: c = new InheritedServerSocketChannelImpl(provider, fd);
180: } else {
181: int port = peerPort0(fdVal);
182: assert port > 0;
183: InetSocketAddress isa = new InetSocketAddress(ia, port);
184: c = new InheritedSocketChannelImpl(provider, fd, isa);
185: }
186: } else {
187: c = new InheritedDatagramChannelImpl(provider, fd);
188: }
189: return c;
190: }
191:
192: private static boolean haveChannel = false;
193: private static Channel channel = null;
194:
195: /*
196: * Returns a Channel representing the inherited channel if the
197: * inherited channel is a stream connected to a network socket.
198: */
199: public static synchronized Channel getChannel() throws IOException {
200: if (devnull < 0) {
201: devnull = open0("/dev/null", O_RDWR);
202: }
203:
204: // If we don't have the channel try to create it
205: if (!haveChannel) {
206: channel = createChannel();
207: haveChannel = true;
208: }
209:
210: // if there is a channel then do the security check before
211: // returning it.
212: if (channel != null) {
213: checkAccess(channel);
214: }
215: return channel;
216: }
217:
218: // -- Native methods --
219:
220: private static native int dup(int fd) throws IOException;
221:
222: private static native void dup2(int fd, int fd2) throws IOException;
223:
224: private static native int open0(String path, int oflag)
225: throws IOException;
226:
227: private static native void close0(int fd) throws IOException;
228:
229: private static native int soType0(int fd);
230:
231: private static native InetAddress peerAddress0(int fd);
232:
233: private static native int peerPort0(int fd);
234:
235: static {
236: Util.load();
237: }
238: }
|