1 /*
   2  * Copyright (c) 2000, 2019, 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.ServerSocket;
  32 import java.net.SocketAddress;
  33 import java.net.SocketOption;
  34 import java.net.SocketTimeoutException;
  35 import java.net.StandardSocketOptions;
  36 import java.nio.channels.AlreadyBoundException;
  37 import java.nio.channels.AsynchronousCloseException;
  38 import java.nio.channels.ClosedChannelException;
  39 import java.nio.channels.IllegalBlockingModeException;
  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 jdk.internal.misc.Strands;
  52 import sun.net.NetHooks;
  53 import sun.net.ext.ExtendedSocketOptions;
  54 
  55 /**
  56  * An implementation of ServerSocketChannels
  57  */
  58 
  59 class ServerSocketChannelImpl
  60     extends ServerSocketChannel
  61     implements SelChImpl
  62 {
  63     // Used to make native close and configure calls
  64     private static final NativeDispatcher nd = new SocketDispatcher();
  65 
  66     // Our file descriptor
  67     private final FileDescriptor fd;
  68     private final int fdVal;
  69 
  70     // Lock held by thread currently blocked on 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_INUSE = 0;
  81     private static final int ST_CLOSING = 1;
  82     private static final int ST_CLOSED = 2;
  83     private int state;
  84 
  85     // ID of native thread currently blocked in this channel, for signalling
  86     private long thread;
  87 
  88     // Binding
  89     private InetSocketAddress localAddress; // null => unbound
  90 
  91     // set true when exclusive binding is on and SO_REUSEADDR is emulated
  92     private boolean isReuseAddress;
  93 
  94     // Our socket adaptor, if any
  95     private ServerSocket socket;
  96 
  97     // lazily set to true when the socket is configured non-blocking
  98     private volatile boolean nonBlocking;
  99 
 100     // -- End of fields protected by stateLock
 101 
 102 
 103     ServerSocketChannelImpl(SelectorProvider sp) {
 104         super(sp);
 105         this.fd = Net.serverSocket(true);
 106         this.fdVal = IOUtil.fdVal(fd);
 107     }
 108 
 109     ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
 110         throws IOException
 111     {
 112         super(sp);
 113         this.fd =  fd;
 114         this.fdVal = IOUtil.fdVal(fd);
 115         if (bound) {
 116             synchronized (stateLock) {
 117                 localAddress = Net.localAddress(fd);
 118             }
 119         }
 120     }
 121 
 122     // @throws ClosedChannelException if channel is closed
 123     private void ensureOpen() throws ClosedChannelException {
 124         if (!isOpen())
 125             throw new ClosedChannelException();
 126     }
 127 
 128     @Override
 129     public ServerSocket socket() {
 130         synchronized (stateLock) {
 131             if (socket == null)
 132                 socket = ServerSocketAdaptor.create(this);
 133             return socket;
 134         }
 135     }
 136 
 137     @Override
 138     public SocketAddress getLocalAddress() throws IOException {
 139         synchronized (stateLock) {
 140             ensureOpen();
 141             return (localAddress == null)
 142                     ? null
 143                     : Net.getRevealedLocalAddress(localAddress);
 144         }
 145     }
 146 
 147     @Override
 148     public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
 149         throws IOException
 150     {
 151         Objects.requireNonNull(name);
 152         if (!supportedOptions().contains(name))
 153             throw new UnsupportedOperationException("'" + name + "' not supported");
 154         if (!name.type().isInstance(value))
 155             throw new IllegalArgumentException("Invalid value '" + value + "'");
 156 
 157         synchronized (stateLock) {
 158             ensureOpen();
 159 
 160             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
 161                 // SO_REUSEADDR emulated when using exclusive bind
 162                 isReuseAddress = (Boolean)value;
 163             } else {
 164                 // no options that require special handling
 165                 Net.setSocketOption(fd, Net.UNSPEC, name, value);
 166             }
 167             return this;
 168         }
 169     }
 170 
 171     @Override
 172     @SuppressWarnings("unchecked")
 173     public <T> T getOption(SocketOption<T> name)
 174         throws IOException
 175     {
 176         Objects.requireNonNull(name);
 177         if (!supportedOptions().contains(name))
 178             throw new UnsupportedOperationException("'" + name + "' not supported");
 179 
 180         synchronized (stateLock) {
 181             ensureOpen();
 182             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
 183                 // SO_REUSEADDR emulated when using exclusive bind
 184                 return (T)Boolean.valueOf(isReuseAddress);
 185             }
 186             // no options that require special handling
 187             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
 188         }
 189     }
 190 
 191     private static class DefaultOptionsHolder {
 192         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
 193 
 194         private static Set<SocketOption<?>> defaultOptions() {
 195             HashSet<SocketOption<?>> set = new HashSet<>();
 196             set.add(StandardSocketOptions.SO_RCVBUF);
 197             set.add(StandardSocketOptions.SO_REUSEADDR);
 198             if (Net.isReusePortAvailable()) {
 199                 set.add(StandardSocketOptions.SO_REUSEPORT);
 200             }
 201             set.addAll(ExtendedSocketOptions.serverSocketOptions());
 202             return Collections.unmodifiableSet(set);
 203         }
 204     }
 205 
 206     @Override
 207     public final Set<SocketOption<?>> supportedOptions() {
 208         return DefaultOptionsHolder.defaultOptions;
 209     }
 210 
 211     @Override
 212     public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
 213         synchronized (stateLock) {
 214             ensureOpen();
 215             if (localAddress != null)
 216                 throw new AlreadyBoundException();
 217             InetSocketAddress isa = (local == null)
 218                                     ? new InetSocketAddress(0)
 219                                     : Net.checkAddress(local);
 220             SecurityManager sm = System.getSecurityManager();
 221             if (sm != null)
 222                 sm.checkListen(isa.getPort());
 223             NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
 224             Net.bind(fd, isa.getAddress(), isa.getPort());
 225             Net.listen(fd, backlog < 1 ? 50 : backlog);
 226             localAddress = Net.localAddress(fd);
 227         }
 228         return this;
 229     }
 230 
 231     /**
 232      * Marks the beginning of an I/O operation that might block.
 233      *
 234      * @throws ClosedChannelException if the channel is closed
 235      * @throws NotYetBoundException if the channel's socket has not been bound yet
 236      */
 237     private void begin(boolean blocking) throws ClosedChannelException {
 238         if (blocking)
 239             begin();  // set blocker to close channel if interrupted
 240         synchronized (stateLock) {
 241             ensureOpen();
 242             if (localAddress == null)
 243                 throw new NotYetBoundException();
 244             if (blocking)
 245                 thread = NativeThread.current();
 246         }
 247     }
 248 
 249     /**
 250      * Marks the end of an I/O operation that may have blocked.
 251      *
 252      * @throws AsynchronousCloseException if the channel was closed due to this
 253      * thread being interrupted on a blocking I/O operation.
 254      */
 255     private void end(boolean blocking, boolean completed)
 256         throws AsynchronousCloseException
 257     {
 258         if (blocking) {
 259             synchronized (stateLock) {
 260                 thread = 0;
 261                 if (state == ST_CLOSING) {
 262                     tryFinishClose();
 263                 }
 264             }
 265             end(completed);
 266         }
 267     }
 268 
 269     @Override
 270     public SocketChannel accept() throws IOException {
 271         int n = 0;
 272         FileDescriptor newfd = new FileDescriptor();
 273         InetSocketAddress[] isaa = new InetSocketAddress[1];
 274 
 275         acceptLock.lock();
 276         try {
 277             boolean blocking = isBlocking();
 278             try {
 279                 begin(blocking);
 280                 lockedConfigureNonBlockingIfFiber();
 281                 n = Net.accept(this.fd, newfd, isaa);
 282                 if (blocking) {
 283                     while (IOStatus.okayToRetry(n) && isOpen()) {
 284                         park(Net.POLLIN);
 285                         n = Net.accept(this.fd, newfd, isaa);
 286                     }
 287                 }
 288             } finally {
 289                 end(blocking, n > 0);
 290                 assert IOStatus.check(n);
 291             }
 292         } finally {
 293             acceptLock.unlock();
 294         }
 295 
 296         if (n > 0) {
 297             return finishAccept(newfd, isaa[0]);
 298         } else {
 299             return null;
 300         }
 301     }
 302 
 303     /**
 304      * Accepts a new connection with a given timeout. This method requires the
 305      * channel to be configured in blocking mode.
 306      *
 307      * @apiNote This method is for use by the socket adaptor.
 308      *
 309      * @param nanos the timeout, in nanoseconds
 310      * @throws IllegalBlockingModeException if the channel is configured non-blocking
 311      * @throws SocketTimeoutException if the timeout expires
 312      */
 313     SocketChannel blockingAccept(long nanos) throws IOException {
 314         int n = 0;
 315         FileDescriptor newfd = new FileDescriptor();
 316         InetSocketAddress[] isaa = new InetSocketAddress[1];
 317 
 318         acceptLock.lock();
 319         try {
 320             // check that channel is configured blocking
 321             if (!isBlocking())
 322                 throw new IllegalBlockingModeException();
 323 
 324             try {
 325                 begin(true);
 326                 // change socket to non-blocking
 327                 lockedConfigureBlocking(false);
 328                 try {
 329                     long startNanos = System.nanoTime();
 330                     n = Net.accept(fd, newfd, isaa);
 331                     while (n == IOStatus.UNAVAILABLE && isOpen()) {
 332                         long remainingNanos = nanos - (System.nanoTime() - startNanos);
 333                         if (remainingNanos <= 0) {
 334                             throw new SocketTimeoutException("Accept timed out");
 335                         }
 336                         park(Net.POLLIN, remainingNanos);
 337                         n = Net.accept(fd, newfd, isaa);
 338                     }
 339                 } finally {
 340                     // restore socket to blocking mode
 341                     lockedConfigureBlocking(true);
 342                 }
 343             } finally {
 344                 end(true, n > 0);
 345             }
 346         } finally {
 347             acceptLock.unlock();
 348         }
 349 
 350         assert n > 0;
 351         return finishAccept(newfd, isaa[0]);
 352     }
 353 
 354     private SocketChannel finishAccept(FileDescriptor newfd, InetSocketAddress isa)
 355         throws IOException
 356     {
 357         try {
 358             // newly accepted socket is initially in blocking mode
 359             IOUtil.configureBlocking(newfd, true);
 360 
 361             // check permitted to accept connections from the remote address
 362             SecurityManager sm = System.getSecurityManager();
 363             if (sm != null) {
 364                 sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
 365             }
 366             return new SocketChannelImpl(provider(), newfd, isa);
 367         } catch (Exception e) {
 368             nd.close(newfd);
 369             throw e;
 370         }
 371     }
 372 
 373     @Override
 374     protected void implConfigureBlocking(boolean block) throws IOException {
 375         acceptLock.lock();
 376         try {
 377             lockedConfigureBlocking(block);
 378         } finally {
 379             acceptLock.unlock();
 380         }
 381     }
 382 
 383     /**
 384      * Adjust the blocking mode while holding acceptLock.
 385      */
 386     private void lockedConfigureBlocking(boolean block) throws IOException {
 387         assert acceptLock.isHeldByCurrentThread();
 388         synchronized (stateLock) {
 389             ensureOpen();
 390             // do nothing if fiber has forced the socket to be non-blocking
 391             if (!nonBlocking) {
 392                 IOUtil.configureBlocking(fd, block);
 393             }
 394         }
 395     }
 396 
 397     /**
 398      * Ensures that the socket is configured non-blocking when the current
 399      * strand is a fiber.
 400      */
 401     private void lockedConfigureNonBlockingIfFiber() throws IOException {
 402         assert acceptLock.isHeldByCurrentThread();
 403         if (!nonBlocking && (Strands.currentStrand() instanceof Fiber)) {
 404             synchronized (stateLock) {
 405                 ensureOpen();
 406                 IOUtil.configureBlocking(fd, false);
 407                 nonBlocking = true;
 408             }
 409         }
 410     }
 411 
 412     /**
 413      * Closes the socket if there are no accept in progress and the channel is
 414      * not registered with a Selector.
 415      */
 416     private boolean tryClose() throws IOException {
 417         assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
 418         if ((thread == 0) && !isRegistered()) {
 419             state = ST_CLOSED;
 420             nd.close(fd);
 421             return true;
 422         } else {
 423             return false;
 424         }
 425     }
 426 
 427     /**
 428      * Invokes tryClose to attempt to close the socket.
 429      *
 430      * This method is used for deferred closing by I/O and Selector operations.
 431      */
 432     private void tryFinishClose() {
 433         try {
 434             tryClose();
 435         } catch (IOException ignore) { }
 436     }
 437 
 438     /**
 439      * Closes this channel when configured in blocking mode.
 440      *
 441      * If there is an accept in progress then the socket is pre-closed and the
 442      * accept thread is signalled, in which case the final close is deferred
 443      * until the accept aborts.
 444      */
 445     private void implCloseBlockingMode() throws IOException {
 446         synchronized (stateLock) {
 447             assert state < ST_CLOSING;
 448             state = ST_CLOSING;
 449             if (!tryClose()) {
 450                 long th = thread;
 451                 if (th != 0) {
 452                     if (NativeThread.isFiber(th))
 453                         Poller.stopPoll(fdVal);
 454                     nd.preClose(fd);
 455                     if (NativeThread.isKernelThread(th))
 456                         NativeThread.signal(th);
 457                 }
 458             }
 459         }
 460     }
 461 
 462     /**
 463      * Closes this channel when configured in non-blocking mode.
 464      *
 465      * If the channel is registered with a Selector then the close is deferred
 466      * until the channel is flushed from all Selectors.
 467      */
 468     private void implCloseNonBlockingMode() throws IOException {
 469         synchronized (stateLock) {
 470             assert state < ST_CLOSING;
 471             state = ST_CLOSING;
 472         }
 473         // wait for any accept to complete before trying to close
 474         acceptLock.lock();
 475         acceptLock.unlock();
 476         synchronized (stateLock) {
 477             if (state == ST_CLOSING) {
 478                 tryClose();
 479             }
 480         }
 481     }
 482 
 483     /**
 484      * Invoked by implCloseChannel to close the channel.
 485      */
 486     @Override
 487     protected void implCloseSelectableChannel() throws IOException {
 488         assert !isOpen();
 489         if (isBlocking()) {
 490             implCloseBlockingMode();
 491         } else {
 492             implCloseNonBlockingMode();
 493         }
 494     }
 495 
 496     @Override
 497     public void kill() {
 498         synchronized (stateLock) {
 499             if (state == ST_CLOSING) {
 500                 tryFinishClose();
 501             }
 502         }
 503     }
 504 
 505     /**
 506      * Returns true if channel's socket is bound
 507      */
 508     boolean isBound() {
 509         synchronized (stateLock) {
 510             return localAddress != null;
 511         }
 512     }
 513 
 514     /**
 515      * Returns the local address, or null if not bound
 516      */
 517     InetSocketAddress localAddress() {
 518         synchronized (stateLock) {
 519             return localAddress;
 520         }
 521     }
 522 
 523     /**
 524      * Translates native poll revent set into a ready operation set
 525      */
 526     public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
 527         int intOps = ski.nioInterestOps();
 528         int oldOps = ski.nioReadyOps();
 529         int newOps = initialOps;
 530 
 531         if ((ops & Net.POLLNVAL) != 0) {
 532             // This should only happen if this channel is pre-closed while a
 533             // selection operation is in progress
 534             // ## Throw an error if this channel has not been pre-closed
 535             return false;
 536         }
 537 
 538         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
 539             newOps = intOps;
 540             ski.nioReadyOps(newOps);
 541             return (newOps & ~oldOps) != 0;
 542         }
 543 
 544         if (((ops & Net.POLLIN) != 0) &&
 545             ((intOps & SelectionKey.OP_ACCEPT) != 0))
 546                 newOps |= SelectionKey.OP_ACCEPT;
 547 
 548         ski.nioReadyOps(newOps);
 549         return (newOps & ~oldOps) != 0;
 550     }
 551 
 552     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
 553         return translateReadyOps(ops, ski.nioReadyOps(), ski);
 554     }
 555 
 556     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
 557         return translateReadyOps(ops, 0, ski);
 558     }
 559 
 560     /**
 561      * Translates an interest operation set into a native poll event set
 562      */
 563     public int translateInterestOps(int ops) {
 564         int newOps = 0;
 565         if ((ops & SelectionKey.OP_ACCEPT) != 0)
 566             newOps |= Net.POLLIN;
 567         return newOps;
 568     }
 569 
 570     public FileDescriptor getFD() {
 571         return fd;
 572     }
 573 
 574     public int getFDVal() {
 575         return fdVal;
 576     }
 577 
 578     public String toString() {
 579         StringBuilder sb = new StringBuilder();
 580         sb.append(this.getClass().getName());
 581         sb.append('[');
 582         if (!isOpen()) {
 583             sb.append("closed");
 584         } else {
 585             synchronized (stateLock) {
 586                 InetSocketAddress addr = localAddress;
 587                 if (addr == null) {
 588                     sb.append("unbound");
 589                 } else {
 590                     sb.append(Net.getRevealedLocalAddressAsString(addr));
 591                 }
 592             }
 593         }
 594         sb.append(']');
 595         return sb.toString();
 596     }
 597 }