Home | History | Annotate | Download | only in nio
      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 java.nio;
     19 
     20 import java.io.FileDescriptor;
     21 import java.io.IOException;
     22 import java.net.PlainServerSocketImpl;
     23 import java.net.ServerSocket;
     24 import java.net.Socket;
     25 import java.net.SocketAddress;
     26 import java.net.SocketImpl;
     27 import java.net.SocketTimeoutException;
     28 import java.nio.channels.ClosedChannelException;
     29 import java.nio.channels.IllegalBlockingModeException;
     30 import java.nio.channels.NotYetBoundException;
     31 import java.nio.channels.ServerSocketChannel;
     32 import java.nio.channels.SocketChannel;
     33 import java.nio.channels.spi.SelectorProvider;
     34 import libcore.io.IoUtils;
     35 
     36 /**
     37  * The default ServerSocketChannel.
     38  */
     39 final class ServerSocketChannelImpl extends ServerSocketChannel implements FileDescriptorChannel {
     40 
     41     private final ServerSocketAdapter socket;
     42     private final SocketImpl impl;
     43 
     44     private boolean isBound = false;
     45 
     46     private final Object acceptLock = new Object();
     47 
     48     public ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
     49         super(sp);
     50         this.socket = new ServerSocketAdapter(this);
     51         this.impl = socket.getImpl$();
     52     }
     53 
     54     @Override public ServerSocket socket() {
     55         return socket;
     56     }
     57 
     58     @Override public SocketChannel accept() throws IOException {
     59         if (!isOpen()) {
     60             throw new ClosedChannelException();
     61         }
     62         if (!isBound) {
     63             throw new NotYetBoundException();
     64         }
     65 
     66         // Create an empty socket channel. This will be populated by ServerSocketAdapter.accept.
     67         SocketChannelImpl result = new SocketChannelImpl(provider(), false);
     68         boolean connected = false;
     69         try {
     70             begin();
     71             synchronized (acceptLock) {
     72                 synchronized (blockingLock()) {
     73                     do {
     74                         try {
     75                             socket.implAccept(result);
     76                             // select successfully, break out immediately.
     77                             break;
     78                         } catch (SocketTimeoutException e) {
     79                             // continue to accept if the channel is in blocking mode.
     80                             // TODO: does this make sense? why does blocking imply no timeouts?
     81                         }
     82                     } while (isBlocking());
     83                 }
     84             }
     85         } finally {
     86             end(result.socket().isConnected());
     87         }
     88         return result.socket().isConnected() ? result : null;
     89     }
     90 
     91     @Override protected void implConfigureBlocking(boolean blocking) throws IOException {
     92         synchronized (blockingLock()) {
     93             IoUtils.setBlocking(impl.getFD$(), blocking);
     94         }
     95     }
     96 
     97     synchronized protected void implCloseSelectableChannel() throws IOException {
     98         if (!socket.isClosed()) {
     99             socket.close();
    100         }
    101     }
    102 
    103     public FileDescriptor getFD() {
    104         return impl.getFD$();
    105     }
    106 
    107     private static class ServerSocketAdapter extends ServerSocket {
    108         private final ServerSocketChannelImpl channelImpl;
    109 
    110         ServerSocketAdapter(ServerSocketChannelImpl aChannelImpl) throws IOException {
    111             this.channelImpl = aChannelImpl;
    112         }
    113 
    114         @Override public void bind(SocketAddress localAddress, int backlog) throws IOException {
    115             super.bind(localAddress, backlog);
    116             channelImpl.isBound = true;
    117         }
    118 
    119         @Override public Socket accept() throws IOException {
    120             if (!channelImpl.isBound) {
    121                 throw new IllegalBlockingModeException();
    122             }
    123             SocketChannel sc = channelImpl.accept();
    124             if (sc == null) {
    125                 throw new IllegalBlockingModeException();
    126             }
    127             return sc.socket();
    128         }
    129 
    130         public Socket implAccept(SocketChannelImpl clientSocketChannel) throws IOException {
    131             Socket clientSocket = clientSocketChannel.socket();
    132             boolean connectOK = false;
    133             try {
    134                 synchronized (this) {
    135                     super.implAccept(clientSocket);
    136                     clientSocketChannel.setConnected();
    137                     clientSocketChannel.setBound(true);
    138                     clientSocketChannel.finishAccept();
    139                 }
    140                 connectOK = true;
    141             } finally {
    142                 if (!connectOK) {
    143                     clientSocket.close();
    144                 }
    145             }
    146             return clientSocket;
    147         }
    148 
    149         @Override public ServerSocketChannel getChannel() {
    150             return channelImpl;
    151         }
    152 
    153         @Override public boolean isBound() {
    154             return channelImpl.isBound;
    155         }
    156 
    157         @Override public void bind(SocketAddress localAddress) throws IOException {
    158             super.bind(localAddress);
    159             channelImpl.isBound = true;
    160         }
    161 
    162         @Override public void close() throws IOException {
    163             synchronized (channelImpl) {
    164                 if (channelImpl.isOpen()) {
    165                     channelImpl.close();
    166                 } else {
    167                     super.close();
    168                 }
    169             }
    170         }
    171     }
    172 }
    173