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 18package java.nio; 19 20import android.system.ErrnoException; 21import java.io.FileDescriptor; 22import java.io.IOException; 23import java.net.InetSocketAddress; 24import java.net.ServerSocket; 25import java.net.Socket; 26import java.net.SocketAddress; 27import java.net.SocketTimeoutException; 28import java.nio.channels.ClosedChannelException; 29import java.nio.channels.IllegalBlockingModeException; 30import java.nio.channels.NotYetBoundException; 31import java.nio.channels.ServerSocketChannel; 32import java.nio.channels.SocketChannel; 33import java.nio.channels.spi.SelectorProvider; 34import java.nio.channels.UnresolvedAddressException; 35import java.nio.channels.UnsupportedAddressTypeException; 36import java.util.Set; 37import libcore.io.IoUtils; 38import static android.system.OsConstants.*; 39 40/** 41 * The default ServerSocketChannel. 42 */ 43final class ServerSocketChannelImpl extends ServerSocketChannel implements FileDescriptorChannel { 44 45 private final ServerSocketAdapter socket; 46 47 private final Object acceptLock = new Object(); 48 49 public ServerSocketChannelImpl(SelectorProvider sp) throws IOException { 50 super(sp); 51 this.socket = new ServerSocketAdapter(this); 52 } 53 54 @Override public ServerSocket socket() { 55 return socket; 56 } 57 58 @Override 59 public SocketChannel accept() throws IOException { 60 if (!isOpen()) { 61 throw new ClosedChannelException(); 62 } 63 if (!socket.isBound()) { 64 throw new NotYetBoundException(); 65 } 66 67 // Create an empty socket channel. This will be populated by ServerSocketAdapter.implAccept. 68 SocketChannelImpl result = new SocketChannelImpl(provider(), false); 69 try { 70 begin(); 71 synchronized (acceptLock) { 72 try { 73 socket.implAccept(result); 74 } catch (SocketTimeoutException e) { 75 if (shouldThrowSocketTimeoutExceptionFromAccept(e)) { 76 throw e; 77 } 78 // Otherwise, this is a non-blocking socket and there's nothing ready, so we'll 79 // fall through and return null. 80 } 81 } 82 } finally { 83 end(result.isConnected()); 84 } 85 return result.isConnected() ? result : null; 86 } 87 88 private boolean shouldThrowSocketTimeoutExceptionFromAccept(SocketTimeoutException e) { 89 if (isBlocking()) { 90 return true; 91 } 92 Throwable cause = e.getCause(); 93 if (cause instanceof ErrnoException) { 94 if (((ErrnoException) cause).errno == EAGAIN) { 95 return false; 96 } 97 } 98 return true; 99 } 100 101 @Override protected void implConfigureBlocking(boolean blocking) throws IOException { 102 IoUtils.setBlocking(socket.getFD$(), blocking); 103 } 104 105 @Override 106 synchronized protected void implCloseSelectableChannel() throws IOException { 107 if (!socket.isClosed()) { 108 socket.close(); 109 } 110 } 111 112 @Override 113 public FileDescriptor getFD() { 114 return socket.getFD$(); 115 } 116 117 private static class ServerSocketAdapter extends ServerSocket { 118 private final ServerSocketChannelImpl channelImpl; 119 120 ServerSocketAdapter(ServerSocketChannelImpl aChannelImpl) throws IOException { 121 this.channelImpl = aChannelImpl; 122 } 123 124 @Override public Socket accept() throws IOException { 125 if (!isBound()) { 126 throw new IllegalBlockingModeException(); 127 } 128 SocketChannel sc = channelImpl.accept(); 129 if (sc == null) { 130 throw new IllegalBlockingModeException(); 131 } 132 return sc.socket(); 133 } 134 135 public Socket implAccept(SocketChannelImpl clientSocketChannel) throws IOException { 136 Socket clientSocket = clientSocketChannel.socket(); 137 boolean connectOK = false; 138 try { 139 synchronized (this) { 140 super.implAccept(clientSocket); 141 142 // Sync the client socket's associated channel state with the Socket and OS. 143 InetSocketAddress remoteAddress = 144 new InetSocketAddress( 145 clientSocket.getInetAddress(), clientSocket.getPort()); 146 clientSocketChannel.onAccept(remoteAddress, false /* updateSocketState */); 147 } 148 connectOK = true; 149 } finally { 150 if (!connectOK) { 151 clientSocket.close(); 152 } 153 } 154 return clientSocket; 155 } 156 157 @Override public ServerSocketChannel getChannel() { 158 return channelImpl; 159 } 160 161 @Override public void close() throws IOException { 162 synchronized (channelImpl) { 163 super.close(); 164 if (channelImpl.isOpen()) { 165 channelImpl.close(); 166 } 167 } 168 } 169 170 private FileDescriptor getFD$() { 171 return super.getImpl$().getFD$(); 172 } 173 } 174} 175