Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package sun.nio.ch;
     27 
     28 import java.io.FileDescriptor;
     29 import java.io.IOException;
     30 import java.net.*;
     31 import java.nio.channels.*;
     32 import java.nio.channels.spi.*;
     33 import java.util.*;
     34 import sun.net.NetHooks;
     35 
     36 
     37 /**
     38  * An implementation of ServerSocketChannels
     39  */
     40 
     41 class ServerSocketChannelImpl
     42     extends ServerSocketChannel
     43     implements SelChImpl
     44 {
     45 
     46     // Used to make native close and configure calls
     47     private static NativeDispatcher nd;
     48 
     49     // Our file descriptor
     50     private final FileDescriptor fd;
     51 
     52     // fd value needed for dev/poll. This value will remain valid
     53     // even after the value in the file descriptor object has been set to -1
     54     private int fdVal;
     55 
     56     // ID of native thread currently blocked in this channel, for signalling
     57     private volatile long thread = 0;
     58 
     59     // Lock held by thread currently blocked in this channel
     60     private final Object lock = new Object();
     61 
     62     // Lock held by any thread that modifies the state fields declared below
     63     // DO NOT invoke a blocking I/O operation while holding this lock!
     64     private final Object stateLock = new Object();
     65 
     66     // -- The following fields are protected by stateLock
     67 
     68     // Channel state, increases monotonically
     69     private static final int ST_UNINITIALIZED = -1;
     70     private static final int ST_INUSE = 0;
     71     private static final int ST_KILLED = 1;
     72     private int state = ST_UNINITIALIZED;
     73 
     74     // Binding
     75     private InetSocketAddress localAddress; // null => unbound
     76 
     77     // set true when exclusive binding is on and SO_REUSEADDR is emulated
     78     private boolean isReuseAddress;
     79 
     80     // Our socket adaptor, if any
     81     ServerSocket socket;
     82 
     83     // -- End of fields protected by stateLock
     84 
     85 
     86     ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
     87         super(sp);
     88         this.fd =  Net.serverSocket(true);
     89         this.fdVal = IOUtil.fdVal(fd);
     90         this.state = ST_INUSE;
     91     }
     92 
     93     ServerSocketChannelImpl(SelectorProvider sp,
     94                             FileDescriptor fd,
     95                             boolean bound)
     96         throws IOException
     97     {
     98         super(sp);
     99         this.fd =  fd;
    100         this.fdVal = IOUtil.fdVal(fd);
    101         this.state = ST_INUSE;
    102         if (bound)
    103             localAddress = Net.localAddress(fd);
    104     }
    105 
    106     public ServerSocket socket() {
    107         synchronized (stateLock) {
    108             if (socket == null)
    109                 socket = ServerSocketAdaptor.create(this);
    110             return socket;
    111         }
    112     }
    113 
    114     @Override
    115     public SocketAddress getLocalAddress() throws IOException {
    116         synchronized (stateLock) {
    117             if (!isOpen())
    118                 throw new ClosedChannelException();
    119             return localAddress == null? localAddress
    120                     : Net.getRevealedLocalAddress(
    121                           Net.asInetSocketAddress(localAddress));
    122         }
    123     }
    124 
    125     @Override
    126     public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
    127         throws IOException
    128     {
    129         if (name == null)
    130             throw new NullPointerException();
    131         if (!supportedOptions().contains(name))
    132             throw new UnsupportedOperationException("'" + name + "' not supported");
    133         synchronized (stateLock) {
    134             if (!isOpen())
    135                 throw new ClosedChannelException();
    136             if (name == StandardSocketOptions.SO_REUSEADDR &&
    137                     Net.useExclusiveBind())
    138             {
    139                 // SO_REUSEADDR emulated when using exclusive bind
    140                 isReuseAddress = (Boolean)value;
    141             } else {
    142                 // no options that require special handling
    143                 Net.setSocketOption(fd, Net.UNSPEC, name, value);
    144             }
    145             return this;
    146         }
    147     }
    148 
    149     @Override
    150     @SuppressWarnings("unchecked")
    151     public <T> T getOption(SocketOption<T> name)
    152         throws IOException
    153     {
    154         if (name == null)
    155             throw new NullPointerException();
    156         if (!supportedOptions().contains(name))
    157             throw new UnsupportedOperationException("'" + name + "' not supported");
    158 
    159         synchronized (stateLock) {
    160             if (!isOpen())
    161                 throw new ClosedChannelException();
    162             if (name == StandardSocketOptions.SO_REUSEADDR &&
    163                     Net.useExclusiveBind())
    164             {
    165                 // SO_REUSEADDR emulated when using exclusive bind
    166                 return (T)Boolean.valueOf(isReuseAddress);
    167             }
    168             // no options that require special handling
    169             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
    170         }
    171     }
    172 
    173     private static class DefaultOptionsHolder {
    174         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
    175 
    176         private static Set<SocketOption<?>> defaultOptions() {
    177             HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2);
    178             set.add(StandardSocketOptions.SO_RCVBUF);
    179             set.add(StandardSocketOptions.SO_REUSEADDR);
    180             return Collections.unmodifiableSet(set);
    181         }
    182     }
    183 
    184     @Override
    185     public final Set<SocketOption<?>> supportedOptions() {
    186         return DefaultOptionsHolder.defaultOptions;
    187     }
    188 
    189     public boolean isBound() {
    190         synchronized (stateLock) {
    191             return localAddress != null;
    192         }
    193     }
    194 
    195     public InetSocketAddress localAddress() {
    196         synchronized (stateLock) {
    197             return localAddress;
    198         }
    199     }
    200 
    201     @Override
    202     public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
    203         synchronized (lock) {
    204             if (!isOpen())
    205                 throw new ClosedChannelException();
    206             if (isBound())
    207                 throw new AlreadyBoundException();
    208             InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :
    209                 Net.checkAddress(local);
    210             SecurityManager sm = System.getSecurityManager();
    211             if (sm != null)
    212                 sm.checkListen(isa.getPort());
    213             NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
    214             Net.bind(fd, isa.getAddress(), isa.getPort());
    215             Net.listen(fd, backlog < 1 ? 50 : backlog);
    216             synchronized (stateLock) {
    217                 localAddress = Net.localAddress(fd);
    218             }
    219         }
    220         return this;
    221     }
    222 
    223     public SocketChannel accept() throws IOException {
    224         synchronized (lock) {
    225             if (!isOpen())
    226                 throw new ClosedChannelException();
    227             if (!isBound())
    228                 throw new NotYetBoundException();
    229             SocketChannel sc = null;
    230 
    231             int n = 0;
    232             FileDescriptor newfd = new FileDescriptor();
    233             InetSocketAddress[] isaa = new InetSocketAddress[1];
    234 
    235             try {
    236                 begin();
    237                 if (!isOpen())
    238                     return null;
    239                 thread = NativeThread.current();
    240                 for (;;) {
    241                     n = accept0(this.fd, newfd, isaa);
    242                     if ((n == IOStatus.INTERRUPTED) && isOpen())
    243                         continue;
    244                     break;
    245                 }
    246             } finally {
    247                 thread = 0;
    248                 end(n > 0);
    249                 assert IOStatus.check(n);
    250             }
    251 
    252             if (n < 1)
    253                 return null;
    254 
    255             IOUtil.configureBlocking(newfd, true);
    256             InetSocketAddress isa = isaa[0];
    257             sc = new SocketChannelImpl(provider(), newfd, isa);
    258             SecurityManager sm = System.getSecurityManager();
    259             if (sm != null) {
    260                 try {
    261                     sm.checkAccept(isa.getAddress().getHostAddress(),
    262                                    isa.getPort());
    263                 } catch (SecurityException x) {
    264                     sc.close();
    265                     throw x;
    266                 }
    267             }
    268             return sc;
    269 
    270         }
    271     }
    272 
    273     protected void implConfigureBlocking(boolean block) throws IOException {
    274         IOUtil.configureBlocking(fd, block);
    275     }
    276 
    277     protected void implCloseSelectableChannel() throws IOException {
    278         synchronized (stateLock) {
    279             if (state != ST_KILLED)
    280                 nd.preClose(fd);
    281             long th = thread;
    282             if (th != 0)
    283                 NativeThread.signal(th);
    284             if (!isRegistered())
    285                 kill();
    286         }
    287     }
    288 
    289     public void kill() throws IOException {
    290         synchronized (stateLock) {
    291             if (state == ST_KILLED)
    292                 return;
    293             if (state == ST_UNINITIALIZED) {
    294                 state = ST_KILLED;
    295                 return;
    296             }
    297             assert !isOpen() && !isRegistered();
    298             nd.close(fd);
    299             state = ST_KILLED;
    300         }
    301     }
    302 
    303     /**
    304      * Translates native poll revent set into a ready operation set
    305      */
    306     public boolean translateReadyOps(int ops, int initialOps,
    307                                      SelectionKeyImpl sk) {
    308         int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
    309         int oldOps = sk.nioReadyOps();
    310         int newOps = initialOps;
    311 
    312         if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
    313             // This should only happen if this channel is pre-closed while a
    314             // selection operation is in progress
    315             // ## Throw an error if this channel has not been pre-closed
    316             return false;
    317         }
    318 
    319         if ((ops & (PollArrayWrapper.POLLERR
    320                     | PollArrayWrapper.POLLHUP)) != 0) {
    321             newOps = intOps;
    322             sk.nioReadyOps(newOps);
    323             return (newOps & ~oldOps) != 0;
    324         }
    325 
    326         if (((ops & PollArrayWrapper.POLLIN) != 0) &&
    327             ((intOps & SelectionKey.OP_ACCEPT) != 0))
    328                 newOps |= SelectionKey.OP_ACCEPT;
    329 
    330         sk.nioReadyOps(newOps);
    331         return (newOps & ~oldOps) != 0;
    332     }
    333 
    334     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
    335         return translateReadyOps(ops, sk.nioReadyOps(), sk);
    336     }
    337 
    338     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
    339         return translateReadyOps(ops, 0, sk);
    340     }
    341 
    342     /**
    343      * Translates an interest operation set into a native poll event set
    344      */
    345     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
    346         int newOps = 0;
    347 
    348         // Translate ops
    349         if ((ops & SelectionKey.OP_ACCEPT) != 0)
    350             newOps |= PollArrayWrapper.POLLIN;
    351         // Place ops into pollfd array
    352         sk.selector.putEventOps(sk, newOps);
    353     }
    354 
    355     public FileDescriptor getFD() {
    356         return fd;
    357     }
    358 
    359     public int getFDVal() {
    360         return fdVal;
    361     }
    362 
    363     public String toString() {
    364         StringBuffer sb = new StringBuffer();
    365         sb.append(this.getClass().getName());
    366         sb.append('[');
    367         if (!isOpen()) {
    368             sb.append("closed");
    369         } else {
    370             synchronized (stateLock) {
    371                 InetSocketAddress addr = localAddress();
    372                 if (addr == null) {
    373                     sb.append("unbound");
    374                 } else {
    375                     sb.append(Net.getRevealedLocalAddressAsString(addr));
    376                 }
    377             }
    378         }
    379         sb.append(']');
    380         return sb.toString();
    381     }
    382 
    383     // -- Native methods --
    384 
    385     // Accepts a new connection, setting the given file descriptor to refer to
    386     // the new socket and setting isaa[0] to the socket's remote address.
    387     // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no
    388     // connections are pending) or IOStatus.INTERRUPTED.
    389     //
    390     private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,
    391                                InetSocketAddress[] isaa)
    392         throws IOException;
    393 
    394     private static native void initIDs();
    395 
    396     static {
    397         initIDs();
    398         nd = new SocketDispatcher();
    399     }
    400 
    401 }
    402