1 /*
   2  * Copyright (c) 2000, 2018, 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.InetSocketAddress;
  31 import java.net.ProtocolFamily;
  32 import java.net.ServerSocket;
  33 import java.net.SocketAddress;
  34 import java.net.SocketOption;
  35 import java.net.StandardProtocolFamily;
  36 import java.net.StandardSocketOptions;
  37 import java.nio.channels.AlreadyBoundException;
  38 import java.nio.channels.ClosedChannelException;
  39 import java.nio.channels.NotYetBoundException;
  40 import java.nio.channels.SelectionKey;
  41 import java.nio.channels.ServerSocketChannel;
  42 import java.nio.channels.SocketChannel;
  43 import java.nio.channels.spi.SelectorProvider;
  44 import java.util.Collections;
  45 import java.util.HashSet;
  46 import java.util.Set;
  47 import java.util.concurrent.locks.ReentrantLock;
  48 
  49 import sun.net.NetHooks;
  50 
  51 /**
  52  * An implementation of ServerSocketChannels
  53  */
  54 
  55 class ServerSocketChannelImpl
  56     extends ServerSocketChannel
  57     implements SelChImpl
  58 {
  59 
  60     // Used to make native close and configure calls
  61     private static NativeDispatcher nd;
  62 
  63     // Our file descriptor
  64     private final FileDescriptor fd;
  65     private final int fdVal;
  66 
  67     // ID of native thread currently blocked in this channel, for signalling
  68     private volatile long thread;
  69 
  70     // Lock held by thread currently blocked in this channel
  71     private final ReentrantLock acceptLock = new ReentrantLock();
  72 
  73     // Lock held by any thread that modifies the state fields declared below
  74     // DO NOT invoke a blocking I/O operation while holding this lock!
  75     private final Object stateLock = new Object();
  76 
  77     // -- The following fields are protected by stateLock
  78 
  79     // Channel state, increases monotonically
  80     private static final int ST_UNINITIALIZED = -1;
  81     private static final int ST_INUSE = 0;
  82     private static final int ST_KILLED = 1;
  83     private int state = ST_UNINITIALIZED;
  84 
  85     // Binding
  86     private InetSocketAddress localAddress; // null => unbound
  87 
  88     // set true when exclusive binding is on and SO_REUSEADDR is emulated
  89     private boolean isReuseAddress;
  90 
  91     // Our socket adaptor, if any
  92     private ServerSocket socket;
  93 
  94     // -- End of fields protected by stateLock
  95 
  96 
  97     ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
  98         super(sp);
  99         this.fd =  Net.serverSocket(true);
 100         this.fdVal = IOUtil.fdVal(fd);
 101         this.state = ST_INUSE;
 102     }
 103 
 104     ServerSocketChannelImpl(SelectorProvider sp,
 105                             FileDescriptor fd,
 106                             boolean bound)
 107         throws IOException
 108     {
 109         super(sp);
 110         this.fd =  fd;
 111         this.fdVal = IOUtil.fdVal(fd);
 112         this.state = ST_INUSE;
 113         if (bound)
 114             localAddress = Net.localAddress(fd);
 115     }
 116 
 117     public ServerSocket socket() {
 118         synchronized (stateLock) {
 119             if (socket == null)
 120                 socket = ServerSocketAdaptor.create(this);
 121             return socket;
 122         }
 123     }
 124 
 125     @Override
 126     public SocketAddress getLocalAddress() throws IOException {
 127         synchronized (stateLock) {
 128             if (!isOpen())
 129                 throw new ClosedChannelException();
 130             return localAddress == null ? localAddress
 131                     : Net.getRevealedLocalAddress(
 132                           Net.asInetSocketAddress(localAddress));
 133         }
 134     }
 135 
 136     @Override
 137     public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
 138         throws IOException
 139     {
 140         if (name == null)
 141             throw new NullPointerException();
 142         if (!supportedOptions().contains(name))
 143             throw new UnsupportedOperationException("'" + name + "' not supported");
 144         synchronized (stateLock) {
 145             if (!isOpen())
 146                 throw new ClosedChannelException();
 147 
 148             if (name == StandardSocketOptions.IP_TOS) {
 149                 ProtocolFamily family = Net.isIPv6Available() ?
 150                     StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
 151                 Net.setSocketOption(fd, family, name, value);
 152                 return this;
 153             }
 154 
 155             if (name == StandardSocketOptions.SO_REUSEADDR &&
 156                     Net.useExclusiveBind())
 157             {
 158                 // SO_REUSEADDR emulated when using exclusive bind
 159                 isReuseAddress = (Boolean)value;
 160             } else {
 161                 // no options that require special handling
 162                 Net.setSocketOption(fd, Net.UNSPEC, name, value);
 163             }
 164             return this;
 165         }
 166     }
 167 
 168     @Override
 169     @SuppressWarnings("unchecked")
 170     public <T> T getOption(SocketOption<T> name)
 171         throws IOException
 172     {
 173         if (name == null)
 174             throw new NullPointerException();
 175         if (!supportedOptions().contains(name))
 176             throw new UnsupportedOperationException("'" + name + "' not supported");
 177 
 178         synchronized (stateLock) {
 179             if (!isOpen())
 180                 throw new ClosedChannelException();
 181             if (name == StandardSocketOptions.SO_REUSEADDR &&
 182                     Net.useExclusiveBind())
 183             {
 184                 // SO_REUSEADDR emulated when using exclusive bind
 185                 return (T)Boolean.valueOf(isReuseAddress);
 186             }
 187             // no options that require special handling
 188             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
 189         }
 190     }
 191 
 192     private static class DefaultOptionsHolder {
 193         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
 194 
 195         private static Set<SocketOption<?>> defaultOptions() {
 196             HashSet<SocketOption<?>> set = new HashSet<>(2);
 197             set.add(StandardSocketOptions.SO_RCVBUF);
 198             set.add(StandardSocketOptions.SO_REUSEADDR);
 199             if (Net.isReusePortAvailable()) {
 200                 set.add(StandardSocketOptions.SO_REUSEPORT);
 201             }
 202             set.add(StandardSocketOptions.IP_TOS);
 203             return Collections.unmodifiableSet(set);
 204         }
 205     }
 206 
 207     @Override
 208     public final Set<SocketOption<?>> supportedOptions() {
 209         return DefaultOptionsHolder.defaultOptions;
 210     }
 211 
 212     public boolean isBound() {
 213         synchronized (stateLock) {
 214             return localAddress != null;
 215         }
 216     }
 217 
 218     public InetSocketAddress localAddress() {
 219         synchronized (stateLock) {
 220             return localAddress;
 221         }
 222     }
 223 
 224     @Override
 225     public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
 226         acceptLock.lock();
 227         try {
 228             if (!isOpen())
 229                 throw new ClosedChannelException();
 230             if (isBound())
 231                 throw new AlreadyBoundException();
 232             InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :
 233                 Net.checkAddress(local);
 234             SecurityManager sm = System.getSecurityManager();
 235             if (sm != null)
 236                 sm.checkListen(isa.getPort());
 237             NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
 238             Net.bind(fd, isa.getAddress(), isa.getPort());
 239             Net.listen(fd, backlog < 1 ? 50 : backlog);
 240             synchronized (stateLock) {
 241                 localAddress = Net.localAddress(fd);
 242             }
 243         } finally {
 244             acceptLock.unlock();
 245         }
 246         return this;
 247     }
 248 
 249     public SocketChannel accept() throws IOException {
 250         acceptLock.lock();
 251         try {
 252             if (!isOpen())
 253                 throw new ClosedChannelException();
 254             if (!isBound())
 255                 throw new NotYetBoundException();
 256             SocketChannel sc = null;
 257 
 258             int n = 0;
 259             FileDescriptor newfd = new FileDescriptor();
 260             InetSocketAddress[] isaa = new InetSocketAddress[1];
 261 
 262             try {
 263                 begin();
 264                 if (!isOpen())
 265                     return null;
 266                 thread = NativeThread.current();
 267                 for (;;) {
 268                     n = accept(this.fd, newfd, isaa);
 269                     if ((n == IOStatus.INTERRUPTED) && isOpen())
 270                         continue;
 271                     break;
 272                 }
 273             } finally {
 274                 thread = 0;
 275                 end(n > 0);
 276                 assert IOStatus.check(n);
 277             }
 278 
 279             if (n < 1)
 280                 return null;
 281 
 282             IOUtil.configureBlocking(newfd, true);
 283             InetSocketAddress isa = isaa[0];
 284             sc = new SocketChannelImpl(provider(), newfd, isa);
 285             SecurityManager sm = System.getSecurityManager();
 286             if (sm != null) {
 287                 try {
 288                     sm.checkAccept(isa.getAddress().getHostAddress(),
 289                                    isa.getPort());
 290                 } catch (SecurityException x) {
 291                     sc.close();
 292                     throw x;
 293                 }
 294             }
 295             return sc;
 296 
 297         } finally {
 298             acceptLock.unlock();
 299         }
 300     }
 301 
 302     protected void implConfigureBlocking(boolean block) throws IOException {
 303         IOUtil.configureBlocking(fd, block);
 304     }
 305 
 306     protected void implCloseSelectableChannel() throws IOException {
 307         synchronized (stateLock) {
 308             if (state != ST_KILLED)
 309                 nd.preClose(fd);
 310             long th = thread;
 311             if (th != 0)
 312                 NativeThread.signal(th);
 313             if (!isRegistered())
 314                 kill();
 315         }
 316     }
 317 
 318     public void kill() throws IOException {
 319         synchronized (stateLock) {
 320             if (state == ST_KILLED)
 321                 return;
 322             if (state == ST_UNINITIALIZED) {
 323                 state = ST_KILLED;
 324                 return;
 325             }
 326             assert !isOpen() && !isRegistered();
 327             nd.close(fd);
 328             state = ST_KILLED;
 329         }
 330     }
 331 
 332     /**
 333      * Translates native poll revent set into a ready operation set
 334      */
 335     public boolean translateReadyOps(int ops, int initialOps,
 336                                      SelectionKeyImpl sk) {
 337         int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
 338         int oldOps = sk.nioReadyOps();
 339         int newOps = initialOps;
 340 
 341         if ((ops & Net.POLLNVAL) != 0) {
 342             // This should only happen if this channel is pre-closed while a
 343             // selection operation is in progress
 344             // ## Throw an error if this channel has not been pre-closed
 345             return false;
 346         }
 347 
 348         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
 349             newOps = intOps;
 350             sk.nioReadyOps(newOps);
 351             return (newOps & ~oldOps) != 0;
 352         }
 353 
 354         if (((ops & Net.POLLIN) != 0) &&
 355             ((intOps & SelectionKey.OP_ACCEPT) != 0))
 356                 newOps |= SelectionKey.OP_ACCEPT;
 357 
 358         sk.nioReadyOps(newOps);
 359         return (newOps & ~oldOps) != 0;
 360     }
 361 
 362     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
 363         return translateReadyOps(ops, sk.nioReadyOps(), sk);
 364     }
 365 
 366     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
 367         return translateReadyOps(ops, 0, sk);
 368     }
 369 
 370     // package-private
 371     int poll(int events, long timeout) throws IOException {
 372         assert Thread.holdsLock(blockingLock()) && !isBlocking();
 373 
 374         acceptLock.lock();
 375         try {
 376             int n = 0;
 377             try {
 378                 begin();
 379                 synchronized (stateLock) {
 380                     if (!isOpen())
 381                         return 0;
 382                     thread = NativeThread.current();
 383                 }
 384                 n = Net.poll(fd, events, timeout);
 385             } finally {
 386                 thread = 0;
 387                 end(n > 0);
 388             }
 389             return n;
 390         } finally {
 391             acceptLock.unlock();
 392         }
 393     }
 394 
 395     /**
 396      * Translates an interest operation set into a native poll event set
 397      */
 398     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
 399         int newOps = 0;
 400 
 401         // Translate ops
 402         if ((ops & SelectionKey.OP_ACCEPT) != 0)
 403             newOps |= Net.POLLIN;
 404         // Place ops into pollfd array
 405         sk.selector.putEventOps(sk, newOps);
 406     }
 407 
 408     public FileDescriptor getFD() {
 409         return fd;
 410     }
 411 
 412     public int getFDVal() {
 413         return fdVal;
 414     }
 415 
 416     public String toString() {
 417         StringBuilder sb = new StringBuilder();
 418         sb.append(this.getClass().getName());
 419         sb.append('[');
 420         if (!isOpen()) {
 421             sb.append("closed");
 422         } else {
 423             synchronized (stateLock) {
 424                 InetSocketAddress addr = localAddress();
 425                 if (addr == null) {
 426                     sb.append("unbound");
 427                 } else {
 428                     sb.append(Net.getRevealedLocalAddressAsString(addr));
 429                 }
 430             }
 431         }
 432         sb.append(']');
 433         return sb.toString();
 434     }
 435 
 436     /**
 437      * Accept a connection on a socket.
 438      *
 439      * @implNote Wrap native call to allow instrumentation.
 440      */
 441     private int accept(FileDescriptor ssfd, FileDescriptor newfd,
 442                        InetSocketAddress[] isaa)
 443         throws IOException
 444     {
 445         return accept0(ssfd, newfd, isaa);
 446     }
 447 
 448     // -- Native methods --
 449 
 450     // Accepts a new connection, setting the given file descriptor to refer to
 451     // the new socket and setting isaa[0] to the socket's remote address.
 452     // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no
 453     // connections are pending) or IOStatus.INTERRUPTED.
 454     //
 455     private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,
 456                                InetSocketAddress[] isaa)
 457         throws IOException;
 458 
 459     private static native void initIDs();
 460 
 461     static {
 462         IOUtil.load();
 463         initIDs();
 464         nd = new SocketDispatcher();
 465     }
 466 
 467 }