Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (c) 2000, 2013, 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 
    137             if (name == StandardSocketOptions.IP_TOS) {
    138                 ProtocolFamily family = Net.isIPv6Available() ?
    139                     StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
    140                 Net.setSocketOption(fd, family, name, value);
    141                 return this;
    142             }
    143 
    144             if (name == StandardSocketOptions.SO_REUSEADDR &&
    145                     Net.useExclusiveBind())
    146             {
    147                 // SO_REUSEADDR emulated when using exclusive bind
    148                 isReuseAddress = (Boolean)value;
    149             } else {
    150                 // no options that require special handling
    151                 Net.setSocketOption(fd, Net.UNSPEC, name, value);
    152             }
    153             return this;
    154         }
    155     }
    156 
    157     @Override
    158     @SuppressWarnings("unchecked")
    159     public <T> T getOption(SocketOption<T> name)
    160         throws IOException
    161     {
    162         if (name == null)
    163             throw new NullPointerException();
    164         if (!supportedOptions().contains(name))
    165             throw new UnsupportedOperationException("'" + name + "' not supported");
    166 
    167         synchronized (stateLock) {
    168             if (!isOpen())
    169                 throw new ClosedChannelException();
    170             if (name == StandardSocketOptions.SO_REUSEADDR &&
    171                     Net.useExclusiveBind())
    172             {
    173                 // SO_REUSEADDR emulated when using exclusive bind
    174                 return (T)Boolean.valueOf(isReuseAddress);
    175             }
    176             // no options that require special handling
    177             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
    178         }
    179     }
    180 
    181     private static class DefaultOptionsHolder {
    182         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
    183 
    184         private static Set<SocketOption<?>> defaultOptions() {
    185             HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2);
    186             set.add(StandardSocketOptions.SO_RCVBUF);
    187             set.add(StandardSocketOptions.SO_REUSEADDR);
    188             set.add(StandardSocketOptions.IP_TOS);
    189             return Collections.unmodifiableSet(set);
    190         }
    191     }
    192 
    193     @Override
    194     public final Set<SocketOption<?>> supportedOptions() {
    195         return DefaultOptionsHolder.defaultOptions;
    196     }
    197 
    198     public boolean isBound() {
    199         synchronized (stateLock) {
    200             return localAddress != null;
    201         }
    202     }
    203 
    204     public InetSocketAddress localAddress() {
    205         synchronized (stateLock) {
    206             return localAddress;
    207         }
    208     }
    209 
    210     @Override
    211     public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
    212         synchronized (lock) {
    213             if (!isOpen())
    214                 throw new ClosedChannelException();
    215             if (isBound())
    216                 throw new AlreadyBoundException();
    217             InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :
    218                 Net.checkAddress(local);
    219             SecurityManager sm = System.getSecurityManager();
    220             if (sm != null)
    221                 sm.checkListen(isa.getPort());
    222             NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
    223             Net.bind(fd, isa.getAddress(), isa.getPort());
    224             Net.listen(fd, backlog < 1 ? 50 : backlog);
    225             synchronized (stateLock) {
    226                 localAddress = Net.localAddress(fd);
    227             }
    228         }
    229         return this;
    230     }
    231 
    232     public SocketChannel accept() throws IOException {
    233         synchronized (lock) {
    234             if (!isOpen())
    235                 throw new ClosedChannelException();
    236             if (!isBound())
    237                 throw new NotYetBoundException();
    238             SocketChannel sc = null;
    239 
    240             int n = 0;
    241             FileDescriptor newfd = new FileDescriptor();
    242             InetSocketAddress[] isaa = new InetSocketAddress[1];
    243 
    244             try {
    245                 begin();
    246                 if (!isOpen())
    247                     return null;
    248                 thread = NativeThread.current();
    249                 for (;;) {
    250                     n = accept(this.fd, newfd, isaa);
    251                     if ((n == IOStatus.INTERRUPTED) && isOpen())
    252                         continue;
    253                     break;
    254                 }
    255             } finally {
    256                 thread = 0;
    257                 end(n > 0);
    258                 assert IOStatus.check(n);
    259             }
    260 
    261             if (n < 1)
    262                 return null;
    263 
    264             IOUtil.configureBlocking(newfd, true);
    265             InetSocketAddress isa = isaa[0];
    266             sc = new SocketChannelImpl(provider(), newfd, isa);
    267             SecurityManager sm = System.getSecurityManager();
    268             if (sm != null) {
    269                 try {
    270                     sm.checkAccept(isa.getAddress().getHostAddress(),
    271                                    isa.getPort());
    272                 } catch (SecurityException x) {
    273                     sc.close();
    274                     throw x;
    275                 }
    276             }
    277             return sc;
    278 
    279         }
    280     }
    281 
    282     protected void implConfigureBlocking(boolean block) throws IOException {
    283         IOUtil.configureBlocking(fd, block);
    284     }
    285 
    286     protected void implCloseSelectableChannel() throws IOException {
    287         synchronized (stateLock) {
    288             if (state != ST_KILLED)
    289                 nd.preClose(fd);
    290             long th = thread;
    291             if (th != 0)
    292                 NativeThread.signal(th);
    293             if (!isRegistered())
    294                 kill();
    295         }
    296     }
    297 
    298     public void kill() throws IOException {
    299         synchronized (stateLock) {
    300             if (state == ST_KILLED)
    301                 return;
    302             if (state == ST_UNINITIALIZED) {
    303                 state = ST_KILLED;
    304                 return;
    305             }
    306             assert !isOpen() && !isRegistered();
    307             nd.close(fd);
    308             state = ST_KILLED;
    309         }
    310     }
    311 
    312     /**
    313      * Translates native poll revent set into a ready operation set
    314      */
    315     public boolean translateReadyOps(int ops, int initialOps,
    316                                      SelectionKeyImpl sk) {
    317         int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
    318         int oldOps = sk.nioReadyOps();
    319         int newOps = initialOps;
    320 
    321         if ((ops & Net.POLLNVAL) != 0) {
    322             // This should only happen if this channel is pre-closed while a
    323             // selection operation is in progress
    324             // ## Throw an error if this channel has not been pre-closed
    325             return false;
    326         }
    327 
    328         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
    329             newOps = intOps;
    330             sk.nioReadyOps(newOps);
    331             return (newOps & ~oldOps) != 0;
    332         }
    333 
    334         if (((ops & Net.POLLIN) != 0) &&
    335             ((intOps & SelectionKey.OP_ACCEPT) != 0))
    336                 newOps |= SelectionKey.OP_ACCEPT;
    337 
    338         sk.nioReadyOps(newOps);
    339         return (newOps & ~oldOps) != 0;
    340     }
    341 
    342     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
    343         return translateReadyOps(ops, sk.nioReadyOps(), sk);
    344     }
    345 
    346     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
    347         return translateReadyOps(ops, 0, sk);
    348     }
    349 
    350     // package-private
    351     int poll(int events, long timeout) throws IOException {
    352         assert Thread.holdsLock(blockingLock()) && !isBlocking();
    353 
    354         synchronized (lock) {
    355             int n = 0;
    356             try {
    357                 begin();
    358                 synchronized (stateLock) {
    359                     if (!isOpen())
    360                         return 0;
    361                     thread = NativeThread.current();
    362                 }
    363                 n = Net.poll(fd, events, timeout);
    364             } finally {
    365                 thread = 0;
    366                 end(n > 0);
    367             }
    368             return n;
    369         }
    370     }
    371 
    372     /**
    373      * Translates an interest operation set into a native poll event set
    374      */
    375     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
    376         int newOps = 0;
    377 
    378         // Translate ops
    379         if ((ops & SelectionKey.OP_ACCEPT) != 0)
    380             newOps |= Net.POLLIN;
    381         // Place ops into pollfd array
    382         sk.selector.putEventOps(sk, newOps);
    383     }
    384 
    385     public FileDescriptor getFD() {
    386         return fd;
    387     }
    388 
    389     public int getFDVal() {
    390         return fdVal;
    391     }
    392 
    393     public String toString() {
    394         StringBuffer sb = new StringBuffer();
    395         sb.append(this.getClass().getName());
    396         sb.append('[');
    397         if (!isOpen()) {
    398             sb.append("closed");
    399         } else {
    400             synchronized (stateLock) {
    401                 InetSocketAddress addr = localAddress();
    402                 if (addr == null) {
    403                     sb.append("unbound");
    404                 } else {
    405                     sb.append(Net.getRevealedLocalAddressAsString(addr));
    406                 }
    407             }
    408         }
    409         sb.append(']');
    410         return sb.toString();
    411     }
    412 
    413     /**
    414      * Accept a connection on a socket.
    415      *
    416      * @implNote Wrap native call to allow instrumentation.
    417      */
    418     private int accept(FileDescriptor ssfd, FileDescriptor newfd,
    419                        InetSocketAddress[] isaa)
    420         throws IOException
    421     {
    422         return accept0(ssfd, newfd, isaa);
    423     }
    424 
    425     // -- Native methods --
    426 
    427     // Accepts a new connection, setting the given file descriptor to refer to
    428     // the new socket and setting isaa[0] to the socket's remote address.
    429     // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no
    430     // connections are pending) or IOStatus.INTERRUPTED.
    431     //
    432     private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,
    433                                InetSocketAddress[] isaa)
    434         throws IOException;
    435 
    436     private static native void initIDs();
    437 
    438     static {
    439         // Android-removed: Code to load native libraries, doesn't make sense on Android.
    440         // IOUtil.load();
    441         initIDs();
    442         nd = new SocketDispatcher();
    443     }
    444 
    445 }
    446