1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.harmony.nio.internal; 19 20 import java.io.FileDescriptor; 21 import java.io.IOException; 22 import java.net.ServerSocket; 23 import java.net.Socket; 24 import java.net.SocketAddress; 25 import java.net.SocketImpl; 26 import java.net.SocketTimeoutException; 27 import java.nio.channels.ClosedChannelException; 28 import java.nio.channels.IllegalBlockingModeException; 29 import java.nio.channels.NotYetBoundException; 30 import java.nio.channels.ServerSocketChannel; 31 import java.nio.channels.SocketChannel; 32 import java.nio.channels.spi.SelectorProvider; 33 import org.apache.harmony.luni.net.PlainServerSocketImpl; 34 import org.apache.harmony.luni.platform.FileDescriptorHandler; 35 import org.apache.harmony.luni.platform.Platform; 36 37 /** 38 * The default ServerSocketChannel. 39 */ 40 public final class ServerSocketChannelImpl 41 extends ServerSocketChannel implements FileDescriptorHandler { 42 43 private final FileDescriptor fd = new FileDescriptor(); 44 private final SocketImpl impl = new PlainServerSocketImpl(fd); 45 private final ServerSocketAdapter socket = new ServerSocketAdapter(impl, this); 46 47 private boolean isBound = false; 48 49 private static class AcceptLock {} 50 private final Object acceptLock = new AcceptLock(); 51 52 public ServerSocketChannelImpl(SelectorProvider sp) throws IOException { 53 super(sp); 54 } 55 56 // for native call 57 @SuppressWarnings("unused") 58 private ServerSocketChannelImpl() throws IOException { 59 this(SelectorProvider.provider()); 60 } 61 62 @Override public ServerSocket socket() { 63 return socket; 64 } 65 66 @Override public SocketChannel accept() throws IOException { 67 if (!isOpen()) { 68 throw new ClosedChannelException(); 69 } 70 if (!isBound) { 71 throw new NotYetBoundException(); 72 } 73 74 // TODO: pass in the SelectorProvider used to create this ServerSocketChannelImpl? 75 // Create an empty socket channel. This will be populated by ServerSocketAdapter.accept. 76 SocketChannelImpl result = new SocketChannelImpl(SelectorProvider.provider(), false); 77 Socket resultSocket = result.socket(); 78 79 try { 80 begin(); 81 synchronized (acceptLock) { 82 synchronized (blockingLock()) { 83 boolean isBlocking = isBlocking(); 84 if (!isBlocking) { 85 int[] tryResult = new int[1]; 86 boolean success = Platform.getNetworkSystem().select( 87 new FileDescriptor[] { fd }, 88 new FileDescriptor[0], 1, 0, 0, tryResult); 89 if (!success || 0 == tryResult[0]) { 90 // no pending connections, returns immediately. 91 return null; 92 } 93 } 94 // do accept. 95 do { 96 try { 97 socket.accept(resultSocket, result); 98 // select successfully, break out immediately. 99 break; 100 } catch (SocketTimeoutException e) { 101 // continue to accept if the channel is in blocking mode. 102 } 103 } while (isBlocking); 104 } 105 } 106 } finally { 107 end(resultSocket.isConnected()); 108 } 109 return result; 110 } 111 112 protected void implConfigureBlocking(boolean blockingMode) throws IOException { 113 // Do nothing here. For real accept() operation in non-blocking mode, 114 // it uses INetworkSystem.select. Whether a channel is blocking can be 115 // decided by isBlocking() method. 116 } 117 118 synchronized protected void implCloseSelectableChannel() throws IOException { 119 if (!socket.isClosed()) { 120 socket.close(); 121 } 122 } 123 124 public FileDescriptor getFD() { 125 return fd; 126 } 127 128 private static class ServerSocketAdapter extends ServerSocket { 129 private final ServerSocketChannelImpl channelImpl; 130 131 ServerSocketAdapter(SocketImpl impl, ServerSocketChannelImpl aChannelImpl) { 132 super(impl); 133 this.channelImpl = aChannelImpl; 134 } 135 136 @Override public void bind(SocketAddress localAddress, int backlog) throws IOException { 137 super.bind(localAddress, backlog); 138 channelImpl.isBound = true; 139 } 140 141 @Override public Socket accept() throws IOException { 142 if (!channelImpl.isBound) { 143 throw new IllegalBlockingModeException(); 144 } 145 SocketChannel sc = channelImpl.accept(); 146 if (null == sc) { 147 throw new IllegalBlockingModeException(); 148 } 149 return sc.socket(); 150 } 151 152 private Socket accept(Socket socket, SocketChannelImpl sockChannel) throws IOException { 153 boolean connectOK = false; 154 try { 155 synchronized (this) { 156 super.implAccept(socket); 157 sockChannel.setConnected(); 158 sockChannel.setBound(true); 159 sockChannel.finishAccept(); 160 } 161 SecurityManager sm = System.getSecurityManager(); 162 if (sm != null) { 163 sm.checkAccept(socket.getInetAddress().getHostAddress(), socket.getPort()); 164 } 165 connectOK = true; 166 } finally { 167 if (!connectOK) { 168 socket.close(); 169 } 170 } 171 return socket; 172 } 173 174 @Override public ServerSocketChannel getChannel() { 175 return channelImpl; 176 } 177 178 @Override public boolean isBound() { 179 return channelImpl.isBound; 180 } 181 182 @Override public void bind(SocketAddress localAddress) throws IOException { 183 super.bind(localAddress); 184 channelImpl.isBound = true; 185 } 186 187 @Override public void close() throws IOException { 188 synchronized (channelImpl) { 189 if (channelImpl.isOpen()) { 190 channelImpl.close(); 191 } else { 192 super.close(); 193 } 194 } 195 } 196 } 197 } 198