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