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.AsynchronousCloseException;
  39 import java.nio.channels.ClosedChannelException;
  40 import java.nio.channels.NotYetBoundException;
  41 import java.nio.channels.SelectionKey;
  42 import java.nio.channels.ServerSocketChannel;
  43 import java.nio.channels.SocketChannel;
  44 import java.nio.channels.spi.SelectorProvider;
  45 import java.util.Collections;
  46 import java.util.HashSet;
  47 import java.util.Objects;
  48 import java.util.Set;
  49 import java.util.concurrent.locks.ReentrantLock;
  50 
  51 import sun.net.NetHooks;
  52 
  53 /**
  54  * An implementation of ServerSocketChannels
  55  */
  56 
  57 public class ServerSocketChannelImpl
  58     extends ServerSocketChannel
  59     implements SelChImpl
  60 {
  61     // Used to make native close and configure calls
  62     protected static NativeDispatcher nd;
  63 
  64     // Our file descriptor
  65     protected FileDescriptor fd;
  66     protected final int fdVal;
  67 
  68     // Lock held by thread currently blocked on this channel
  69     protected final ReentrantLock acceptLock = new ReentrantLock();
  70 
  71     // Lock held by any thread that modifies the state fields declared below
  72     // DO NOT invoke a blocking I/O operation while holding this lock!
  73     protected final Object stateLock = new Object();
  74 
  75     // -- The following fields are protected by stateLock
  76 
  77     // Channel state, increases monotonically
  78     protected static final int ST_INUSE = 0;
  79     protected static final int ST_CLOSING = 1;
  80     protected static final int ST_KILLPENDING = 2;
  81     protected static final int ST_KILLED = 3;
  82     protected int state;
  83 
  84     // ID of native thread currently blocked in this channel, for signalling
  85     protected long thread;
  86 
  87     // Binding
  88     protected InetSocketAddress localAddress; // null => unbound
  89 
  90     // set true when exclusive binding is on and SO_REUSEADDR is emulated
  91     protected boolean isReuseAddress;
  92 
  93     // Our socket adaptor, if any
  94     protected ServerSocket socket;
  95 
  96     // -- End of fields protected by stateLock
  97 
  98 
  99     protected ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
 100         super(sp);
 101         this.fd =  createFD();
 102         this.fdVal = IOUtil.fdVal(fd);
 103     }
 104 
 105     protected ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
 106         throws IOException
 107     {
 108         super(sp);
 109         this.fd =  fd;
 110         this.fdVal = IOUtil.fdVal(fd);
 111         if (bound) {
 112             synchronized (stateLock) {
 113                 localAddress = createLocalAddress(fd);
 114             }
 115         }
 116     }
 117 
 118     protected FileDescriptor createFD() throws IOException {
 119         return Net.serverSocket(true);
 120     }
 121 
 122     protected InetSocketAddress createLocalAddress(FileDescriptor fd)
 123         throws IOException {
 124         return Net.localAddress(fd);
 125     }
 126 
 127     // @throws ClosedChannelException if channel is closed
 128     protected void ensureOpen() throws ClosedChannelException {
 129         if (!isOpen())
 130             throw new ClosedChannelException();
 131     }
 132 
 133     @Override
 134     public ServerSocket socket() {
 135         synchronized (stateLock) {
 136             if (socket == null)
 137                 socket = ServerSocketAdaptor.create(this);
 138             return socket;
 139         }
 140     }
 141 
 142     @Override
 143     public SocketAddress getLocalAddress() throws IOException {
 144         synchronized (stateLock) {
 145             ensureOpen();
 146             return (localAddress == null)
 147                     ? null
 148                     : Net.getRevealedLocalAddress(localAddress);
 149         }
 150     }
 151 
 152     @Override
 153     public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
 154         throws IOException
 155     {
 156         Objects.requireNonNull(name);
 157         if (!supportedOptions().contains(name))
 158             throw new UnsupportedOperationException("'" + name + "' not supported");
 159         synchronized (stateLock) {
 160             ensureOpen();
 161 
 162             if (name == StandardSocketOptions.IP_TOS) {
 163                 ProtocolFamily family = Net.isIPv6Available() ?
 164                     StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
 165                 Net.setSocketOption(fd, family, name, value);
 166                 return this;
 167             }
 168 
 169             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
 170                 // SO_REUSEADDR emulated when using exclusive bind
 171                 isReuseAddress = (Boolean)value;
 172             } else {
 173                 // no options that require special handling
 174                 Net.setSocketOption(fd, Net.UNSPEC, name, value);
 175             }
 176             return this;
 177         }
 178     }
 179 
 180     @Override
 181     @SuppressWarnings("unchecked")
 182     public <T> T getOption(SocketOption<T> name)
 183         throws IOException
 184     {
 185         Objects.requireNonNull(name);
 186         if (!supportedOptions().contains(name))
 187             throw new UnsupportedOperationException("'" + name + "' not supported");
 188 
 189         synchronized (stateLock) {
 190             ensureOpen();
 191             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
 192                 // SO_REUSEADDR emulated when using exclusive bind
 193                 return (T)Boolean.valueOf(isReuseAddress);
 194             }
 195             // no options that require special handling
 196             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
 197         }
 198     }
 199 
 200     private static class DefaultOptionsHolder {
 201         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
 202 
 203         private static Set<SocketOption<?>> defaultOptions() {
 204             HashSet<SocketOption<?>> set = new HashSet<>();
 205             set.add(StandardSocketOptions.SO_RCVBUF);
 206             set.add(StandardSocketOptions.SO_REUSEADDR);
 207             if (Net.isReusePortAvailable()) {
 208                 set.add(StandardSocketOptions.SO_REUSEPORT);
 209             }
 210             set.add(StandardSocketOptions.IP_TOS);
 211             return Collections.unmodifiableSet(set);
 212         }
 213     }
 214 
 215     @Override
 216     public Set<SocketOption<?>> supportedOptions() {
 217         return DefaultOptionsHolder.defaultOptions;
 218     }
 219 
 220     @Override
 221     public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
 222         synchronized (stateLock) {
 223             ensureOpen();
 224             if (localAddress != null)
 225                 throw new AlreadyBoundException();
 226             InetSocketAddress isa = (local == null)
 227                                     ? new InetSocketAddress(0)
 228                                     : Net.checkAddress(local);
 229             SecurityManager sm = System.getSecurityManager();
 230             if (sm != null)
 231                 sm.checkListen(isa.getPort());
 232             NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
 233             Net.bind(fd, isa.getAddress(), isa.getPort());
 234             Net.listen(fd, backlog < 1 ? 50 : backlog);
 235             localAddress = Net.localAddress(fd);
 236         }
 237         return this;
 238     }
 239 
 240     /**
 241      * Marks the beginning of an I/O operation that might block.
 242      *
 243      * @throws ClosedChannelException if the channel is closed
 244      * @throws NotYetBoundException if the channel's socket has not been bound yet
 245      */
 246     protected void begin(boolean blocking) throws ClosedChannelException {
 247         if (blocking)
 248             begin();  // set blocker to close channel if interrupted
 249         synchronized (stateLock) {
 250             ensureOpen();
 251             if (localAddress == null)
 252                 throw new NotYetBoundException();
 253             if (blocking)
 254                 thread = NativeThread.current();
 255         }
 256     }
 257 
 258     /**
 259      * Marks the end of an I/O operation that may have blocked.
 260      *
 261      * @throws AsynchronousCloseException if the channel was closed due to this
 262      * thread being interrupted on a blocking I/O operation.
 263      */
 264     protected void end(boolean blocking, boolean completed)
 265         throws AsynchronousCloseException
 266     {
 267         if (blocking) {
 268             synchronized (stateLock) {
 269                 thread = 0;
 270                 // notify any thread waiting in implCloseSelectableChannel
 271                 if (state == ST_CLOSING) {
 272                     stateLock.notifyAll();
 273                 }
 274             }
 275             end(completed);
 276         }
 277     }
 278 
 279     @Override
 280     public SocketChannel accept() throws IOException {
 281         acceptLock.lock();
 282         try {
 283             int n = 0;
 284             FileDescriptor newfd = new FileDescriptor();
 285             InetSocketAddress[] isaa = new InetSocketAddress[1];
 286 
 287             boolean blocking = isBlocking();
 288             try {
 289                 begin(blocking);
 290                 do {
 291                     n = accept(this.fd, newfd, isaa);
 292                 } while (n == IOStatus.INTERRUPTED && isOpen());
 293             } finally {
 294                 end(blocking, n > 0);
 295                 assert IOStatus.check(n);
 296             }
 297 
 298             if (n < 1)
 299                 return null;
 300 
 301             // newly accepted socket is initially in blocking mode
 302             IOUtil.configureBlocking(newfd, true);
 303 
 304             InetSocketAddress isa = isaa[0];
 305             SocketChannel sc = new SocketChannelImpl(provider(), newfd, isa);
 306 
 307             // check permitted to accept connections from the remote address
 308             SecurityManager sm = System.getSecurityManager();
 309             if (sm != null) {
 310                 try {
 311                     sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
 312                 } catch (SecurityException x) {
 313                     sc.close();
 314                     throw x;
 315                 }
 316             }
 317             return sc;
 318 
 319         } finally {
 320             acceptLock.unlock();
 321         }
 322     }
 323 
 324     @Override
 325     protected void implConfigureBlocking(boolean block) throws IOException {
 326         acceptLock.lock();
 327         try {
 328             synchronized (stateLock) {
 329                 ensureOpen();
 330                 IOUtil.configureBlocking(fd, block);
 331             }
 332         } finally {
 333             acceptLock.unlock();
 334         }
 335     }
 336 
 337     /**
 338      * Invoked by implCloseChannel to close the channel.
 339      *
 340      * This method waits for outstanding I/O operations to complete. When in
 341      * blocking mode, the socket is pre-closed and the threads in blocking I/O
 342      * operations are signalled to ensure that the outstanding I/O operations
 343      * complete quickly.
 344      *
 345      * The socket is closed by this method when it is not registered with a
 346      * Selector. Note that a channel configured blocking may be registered with
 347      * a Selector. This arises when a key is canceled and the channel configured
 348      * to blocking mode before the key is flushed from the Selector.
 349      */
 350     @Override
 351     protected void implCloseSelectableChannel() throws IOException {
 352         assert !isOpen();
 353 
 354         boolean interrupted = false;
 355         boolean blocking;
 356 
 357         // set state to ST_CLOSING
 358         synchronized (stateLock) {
 359             assert state < ST_CLOSING;
 360             state = ST_CLOSING;
 361             blocking = isBlocking();
 362         }
 363 
 364         // wait for any outstanding accept to complete
 365         if (blocking) {
 366             synchronized (stateLock) {
 367                 assert state == ST_CLOSING;
 368                 long th = thread;
 369                 if (th != 0) {
 370                     nd.preClose(fd);
 371                     NativeThread.signal(th);
 372 
 373                     // wait for accept operation to end
 374                     while (thread != 0) {
 375                         try {
 376                             stateLock.wait();
 377                         } catch (InterruptedException e) {
 378                             interrupted = true;
 379                         }
 380                     }
 381                 }
 382             }
 383         } else {
 384             // non-blocking mode: wait for accept to complete
 385             acceptLock.lock();
 386             acceptLock.unlock();
 387         }
 388 
 389         // set state to ST_KILLPENDING
 390         synchronized (stateLock) {
 391             assert state == ST_CLOSING;
 392             state = ST_KILLPENDING;
 393         }
 394 
 395         // close socket if not registered with Selector
 396         if (!isRegistered())
 397             kill();
 398 
 399         // restore interrupt status
 400         if (interrupted)
 401             Thread.currentThread().interrupt();
 402     }
 403 
 404     @Override
 405     public void kill() throws IOException {
 406         synchronized (stateLock) {
 407             if (state == ST_KILLPENDING) {
 408                 state = ST_KILLED;
 409                 nd.close(fd);
 410             }
 411         }
 412     }
 413 
 414     /**
 415      * Returns true if channel's socket is bound
 416      */
 417     boolean isBound() {
 418         synchronized (stateLock) {
 419             return localAddress != null;
 420         }
 421     }
 422 
 423     /**
 424      * Returns the local address, or null if not bound
 425      */
 426     InetSocketAddress localAddress() {
 427         synchronized (stateLock) {
 428             return localAddress;
 429         }
 430     }
 431 
 432     /**
 433      * Poll this channel's socket for a new connection up to the given timeout.
 434      * @return {@code true} if there is a connection to accept
 435      */
 436     boolean pollAccept(long timeout) throws IOException {
 437         assert Thread.holdsLock(blockingLock()) && isBlocking();
 438         acceptLock.lock();
 439         try {
 440             boolean polled = false;
 441             try {
 442                 begin(true);
 443                 int events = Net.poll(fd, Net.POLLIN, timeout);
 444                 polled = (events != 0);
 445             } finally {
 446                 end(true, polled);
 447             }
 448             return polled;
 449         } finally {
 450             acceptLock.unlock();
 451         }
 452     }
 453 
 454     /**
 455      * Translates native poll revent set into a ready operation set
 456      */
 457     public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
 458         int intOps = ski.nioInterestOps();
 459         int oldOps = ski.nioReadyOps();
 460         int newOps = initialOps;
 461 
 462         if ((ops & Net.POLLNVAL) != 0) {
 463             // This should only happen if this channel is pre-closed while a
 464             // selection operation is in progress
 465             // ## Throw an error if this channel has not been pre-closed
 466             return false;
 467         }
 468 
 469         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
 470             newOps = intOps;
 471             ski.nioReadyOps(newOps);
 472             return (newOps & ~oldOps) != 0;
 473         }
 474 
 475         if (((ops & Net.POLLIN) != 0) &&
 476             ((intOps & SelectionKey.OP_ACCEPT) != 0))
 477                 newOps |= SelectionKey.OP_ACCEPT;
 478 
 479         ski.nioReadyOps(newOps);
 480         return (newOps & ~oldOps) != 0;
 481     }
 482 
 483     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
 484         return translateReadyOps(ops, ski.nioReadyOps(), ski);
 485     }
 486 
 487     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
 488         return translateReadyOps(ops, 0, ski);
 489     }
 490 
 491     /**
 492      * Translates an interest operation set into a native poll event set
 493      */
 494     public int translateInterestOps(int ops) {
 495         int newOps = 0;
 496         if ((ops & SelectionKey.OP_ACCEPT) != 0)
 497             newOps |= Net.POLLIN;
 498         return newOps;
 499     }
 500 
 501     public FileDescriptor getFD() {
 502         return fd;
 503     }
 504 
 505     public int getFDVal() {
 506         return fdVal;
 507     }
 508 
 509     public String toString() {
 510         StringBuilder sb = new StringBuilder();
 511         sb.append(this.getClass().getName());
 512         sb.append('[');
 513         if (!isOpen()) {
 514             sb.append("closed");
 515         } else {
 516             synchronized (stateLock) {
 517                 InetSocketAddress addr = localAddress;
 518                 if (addr == null) {
 519                     sb.append("unbound");
 520                 } else {
 521                     sb.append(Net.getRevealedLocalAddressAsString(addr));
 522                 }
 523             }
 524         }
 525         sb.append(']');
 526         return sb.toString();
 527     }
 528 
 529     /**
 530      * Accept a connection on a socket.
 531      *
 532      * @implNote Wrap native call to allow instrumentation.
 533      */
 534     private int accept(FileDescriptor ssfd,
 535                        FileDescriptor newfd,
 536                        InetSocketAddress[] isaa)
 537         throws IOException
 538     {
 539         return accept0(ssfd, newfd, isaa);
 540     }
 541 
 542     // -- Native methods --
 543 
 544     // Accepts a new connection, setting the given file descriptor to refer to
 545     // the new socket and setting isaa[0] to the socket's remote address.
 546     // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no
 547     // connections are pending) or IOStatus.INTERRUPTED.
 548     //
 549     private native int accept0(FileDescriptor ssfd,
 550                                FileDescriptor newfd,
 551                                InetSocketAddress[] isaa)
 552         throws IOException;
 553 
 554     private static native void initIDs();
 555 
 556     static {
 557         IOUtil.load();
 558         initIDs();
 559         nd = new SocketDispatcher();
 560     }
 561 
 562 }