001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.harmony.nio.internal;
019:
020: import java.io.FileDescriptor;
021: import java.io.IOException;
022: import java.net.ServerSocket;
023: import java.net.Socket;
024: import java.net.SocketAddress;
025: import java.net.SocketImpl;
026: import java.net.SocketTimeoutException;
027: import java.nio.channels.ClosedChannelException;
028: import java.nio.channels.IllegalBlockingModeException;
029: import java.nio.channels.NotYetBoundException;
030: import java.nio.channels.ServerSocketChannel;
031: import java.nio.channels.SocketChannel;
032: import java.nio.channels.spi.SelectorProvider;
033:
034: import org.apache.harmony.luni.net.NetUtil;
035: import org.apache.harmony.luni.net.SocketImplProvider;
036: import org.apache.harmony.luni.platform.FileDescriptorHandler;
037: import org.apache.harmony.luni.platform.Platform;
038:
039: /*
040: * The default implementation class of java.nio.channels.ServerSocketChannel.
041: */
042: public class ServerSocketChannelImpl extends ServerSocketChannel
043: implements FileDescriptorHandler {
044:
045: // ----------------------------------------------------
046: // Class variables
047: // ----------------------------------------------------
048:
049: // status un-init, not initialized.
050: private static final int SERVER_STATUS_UNINIT = -1;
051:
052: // status after open and before closed.
053: private static final int SERVER_STATUS_OPEN = 0;
054:
055: // status closed.
056: private static final int SERVER_STATUS_CLOSED = 1;
057:
058: // -------------------------------------------------------------------
059: // Instance variables
060: // -------------------------------------------------------------------
061:
062: // The fd to interact with native code
063: private final FileDescriptor fd;
064:
065: // The internal ServerSocket
066: private final ServerSocket socket;
067:
068: private final SocketImpl impl;
069:
070: int status = SERVER_STATUS_UNINIT;
071:
072: // whether the socket is bound
073: boolean isBound = false;
074:
075: // lock for accept
076: private static class AcceptLock {
077: }
078:
079: private final Object acceptLock = new AcceptLock();
080:
081: // ----------------------------------------------------
082: // Constructor
083: // ----------------------------------------------------
084:
085: /*
086: * Constructor
087: */
088: public ServerSocketChannelImpl(SelectorProvider sp)
089: throws IOException {
090: super (sp);
091: status = SERVER_STATUS_OPEN;
092: fd = new FileDescriptor();
093: Platform.getNetworkSystem().createServerStreamSocket(fd,
094: NetUtil.preferIPv4Stack());
095: impl = SocketImplProvider.getServerSocketImpl(fd);
096: socket = new ServerSocketAdapter(impl, this );
097: }
098:
099: // for native call
100: @SuppressWarnings("unused")
101: private ServerSocketChannelImpl() throws IOException {
102: super (SelectorProvider.provider());
103: status = SERVER_STATUS_OPEN;
104: fd = new FileDescriptor();
105: impl = SocketImplProvider.getServerSocketImpl(fd);
106: socket = new ServerSocketAdapter(impl, this );
107: isBound = false;
108: }
109:
110: // ----------------------------------------------------
111: // Methods
112: // ----------------------------------------------------
113:
114: /*
115: * Getting the internal Socket If we have not the socket, we create a new
116: * one.
117: */
118: public ServerSocket socket() {
119: return socket;
120: }
121:
122: /*
123: *
124: * @see java.nio.channels.ServerSocketChannel#accept()
125: */
126: public SocketChannel accept() throws IOException {
127: if (!isOpen()) {
128: throw new ClosedChannelException();
129: }
130: if (!isBound) {
131: throw new NotYetBoundException();
132: }
133:
134: SocketChannel sockChannel = new SocketChannelImpl(
135: SelectorProvider.provider(), false);
136: Socket socketGot = sockChannel.socket();
137:
138: try {
139: begin();
140:
141: synchronized (acceptLock) {
142: synchronized (blockingLock()) {
143: boolean isBlocking = isBlocking();
144: if (!isBlocking) {
145: // for non blocking mode, use select to see whether
146: // there are any pending connections.
147: int[] tryResult = Platform
148: .getNetworkSystem()
149: .select(
150: new FileDescriptor[] { this .fd },
151: new FileDescriptor[0], 0);
152: if (0 == tryResult.length || 0 == tryResult[0]) {
153: // no pending connections, returns immediately.
154: return null;
155: }
156: }
157: // do accept.
158: do {
159: try {
160: ((ServerSocketAdapter) socket).accept(
161: socketGot,
162: (SocketChannelImpl) sockChannel);
163: // select successfully, break out immediately.
164: break;
165: } catch (SocketTimeoutException e) {
166: // continue to accept if the channel is in blocking
167: // mode.
168: }
169: } while (isBlocking);
170: }
171: }
172: } finally {
173: end(socketGot.isConnected());
174: }
175: return sockChannel;
176: }
177:
178: // -------------------------------------------------------------------
179: // Protected inherited methods
180: // -------------------------------------------------------------------
181:
182: /*
183: * @see java.nio.channels.spi.AbstractSelectableChannel#implConfigureBlocking
184: *
185: * (boolean)
186: */
187: protected void implConfigureBlocking(boolean blockingMode)
188: throws IOException {
189: // Do nothing here. For real accept() operation in nonblocking mode,
190: // it uses INetworkSystem.select. Whether a channel is blocking can be
191: // decided by isBlocking() method.
192: }
193:
194: /*
195: *
196: * @see java.nio.channels.spi.AbstractSelectableChannel#implCloseSelectableChannel()
197: */
198: synchronized protected void implCloseSelectableChannel()
199: throws IOException {
200: status = SERVER_STATUS_CLOSED;
201: if (!socket.isClosed()) {
202: socket.close();
203: }
204: }
205:
206: /*
207: * Gets the FileDescriptor
208: */
209: public FileDescriptor getFD() {
210: return fd;
211: }
212:
213: // ----------------------------------------------------
214: // Adapter classes.
215: // ----------------------------------------------------
216:
217: /*
218: * The adapter class of ServerSocket.
219: */
220: private class ServerSocketAdapter extends ServerSocket {
221: /*
222: * The related ServerSocketChannel.
223: */
224: ServerSocketChannelImpl channelImpl;
225:
226: /*
227: * The Constructor.
228: */
229: ServerSocketAdapter(SocketImpl impl,
230: ServerSocketChannelImpl aChannelImpl) {
231: super (impl);
232: this .channelImpl = aChannelImpl;
233: }
234:
235: /*
236: *
237: * @see java.net.ServerSocket#bind(java.net.SocketAddress, int)
238: */
239: public void bind(SocketAddress localAddr, int backlog)
240: throws IOException {
241: super .bind(localAddr, backlog);
242: channelImpl.isBound = true;
243: }
244:
245: /*
246: * @see java.net.ServerSocket#accept()
247: *
248: * If the channel is in non-blocking mode and there is no connection
249: * ready to be accepted, invoking this method will cause an
250: * IllegalBlockingModeException.
251: */
252: public Socket accept() throws IOException {
253: if (!isBound) {
254: throw new IllegalBlockingModeException();
255: }
256: SocketChannel sc = channelImpl.accept();
257: if (null == sc) {
258: throw new IllegalBlockingModeException();
259: }
260: return sc.socket();
261: }
262:
263: /*
264: * do the accept.
265: */
266: private Socket accept(Socket aSocket,
267: SocketChannelImpl sockChannel) throws IOException {
268: // a new socket is pass in so we do not need to "Socket aSocket =
269: // new Socket();"
270: boolean connectOK = false;
271: try {
272: synchronized (this ) {
273: super .implAccept(aSocket);
274: sockChannel.setConnected();
275: sockChannel.setBound(true);
276: }
277: SecurityManager sm = System.getSecurityManager();
278: if (sm != null) {
279: sm.checkAccept(aSocket.getInetAddress()
280: .getHostAddress(), aSocket.getPort());
281: }
282: connectOK = true;
283: } finally {
284: if (!connectOK) {
285: aSocket.close();
286: }
287: }
288: return aSocket;
289: }
290:
291: /*
292: * getting internal channel.
293: */
294: public ServerSocketChannel getChannel() {
295: return channelImpl;
296: }
297:
298: /*
299: *
300: * @see java.net.ServerSocket#isBound()
301: */
302: public boolean isBound() {
303: return channelImpl.isBound;
304: }
305:
306: /*
307: *
308: * @see java.net.ServerSocket#bind(java.net.SocketAddress)
309: */
310: public void bind(SocketAddress localAddr) throws IOException {
311: super .bind(localAddr);
312: channelImpl.isBound = true;
313: }
314:
315: /*
316: * @see java.net.ServerSocket#close()
317: */
318: public void close() throws IOException {
319: synchronized (channelImpl) {
320: if (channelImpl.isOpen()) {
321: channelImpl.close();
322: } else {
323: super.close();
324: }
325: channelImpl.status = SERVER_STATUS_CLOSED;
326: }
327: }
328: }
329: }
|