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 class ServerSocketChannelImpl
  58     extends ServerSocketChannel
  59     implements SelChImpl
  60 {
  61     // Used to make native close and configure calls
  62     private static NativeDispatcher nd;
  63 
  64     // Our file descriptor
  65     private final FileDescriptor fd;
  66     private final int fdVal;
  67 
  68     // Lock held by thread currently blocked on this channel
  69     private 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     private final Object stateLock = new Object();
  74 
  75     // -- The following fields are protected by stateLock
  76 
  77     // Channel state, increases monotonically
  78     private static final int ST_INUSE = 0;
  79     private static final int ST_CLOSING = 1;
  80     private static final int ST_KILLPENDING = 2;
  81     private static final int ST_KILLED = 3;
  82     private int state;
  83 
  84     // ID of native thread currently blocked in this channel, for signalling
  85     private long thread;
  86 
  87     // Binding
  88     private InetSocketAddress localAddress; // null => unbound
  89 
  90     // set true when exclusive binding is on and SO_REUSEADDR is emulated
  91     private boolean isReuseAddress;
  92 
  93     // Our socket adaptor, if any
  94     private ServerSocket socket;
  95 
  96     // -- End of fields protected by stateLock
  97 
  98 
  99     ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
 100         super(sp);
 101         this.fd =  Net.serverSocket(true);
 102         this.fdVal = IOUtil.fdVal(fd);
 103     }
 104 
 105     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 = Net.localAddress(fd);
 114             }
 115         }
 116     }
 117 
 118     // @throws ClosedChannelException if channel is closed
 119     private void ensureOpen() throws ClosedChannelException {
 120         if (!isOpen())
 121             throw new ClosedChannelException();
 122     }
 123 
 124     @Override
 125     public ServerSocket socket() {
 126         synchronized (stateLock) {
 127             if (socket == null)
 128                 socket = ServerSocketAdaptor.create(this);
 129             return socket;
 130         }
 131     }
 132 
 133     @Override
 134     public SocketAddress getLocalAddress() throws IOException {
 135         synchronized (stateLock) {
 136             ensureOpen();
 137             return (localAddress == null)
 138                     ? null
 139                     : Net.getRevealedLocalAddress(localAddress);
 140         }
 141     }
 142 
 143     @Override
 144     public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
 145         throws IOException
 146     {
 147         Objects.requireNonNull(name);
 148         if (!supportedOptions().contains(name))
 149             throw new UnsupportedOperationException("'" + name + "' not supported");
 150         synchronized (stateLock) {
 151             ensureOpen();
 152 
 153             if (name == StandardSocketOptions.IP_TOS) {
 154                 ProtocolFamily family = Net.isIPv6Available() ?
 155                     StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
 156                 Net.setSocketOption(fd, family, name, value);
 157                 return this;
 158             }
 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.add(StandardSocketOptions.IP_TOS);
 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                 // notify any thread waiting in implCloseSelectableChannel
 262                 if (state == ST_CLOSING) {
 263                     stateLock.notifyAll();
 264                 }
 265             }
 266             end(completed);
 267         }
 268     }
 269 
 270     @Override
 271     public SocketChannel accept() throws IOException {
 272         acceptLock.lock();
 273         try {
 274             int n = 0;
 275             FileDescriptor newfd = new FileDescriptor();
 276             InetSocketAddress[] isaa = new InetSocketAddress[1];
 277 
 278             boolean blocking = isBlocking();
 279             try {
 280                 begin(blocking);
 281                 do {
 282                     n = accept(this.fd, newfd, isaa);
 283                 } while (n == IOStatus.INTERRUPTED && isOpen());
 284             } finally {
 285                 end(blocking, n > 0);
 286                 assert IOStatus.check(n);
 287             }
 288 
 289             if (n < 1)
 290                 return null;
 291 
 292             // newly accepted socket is initially in blocking mode
 293             IOUtil.configureBlocking(newfd, true);
 294 
 295             InetSocketAddress isa = isaa[0];
 296             SocketChannel sc = new SocketChannelImpl(provider(), newfd, isa);
 297 
 298             // check permitted to accept connections from the remote address
 299             SecurityManager sm = System.getSecurityManager();
 300             if (sm != null) {
 301                 try {
 302                     sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
 303                 } catch (SecurityException x) {
 304                     sc.close();
 305                     throw x;
 306                 }
 307             }
 308             return sc;
 309 
 310         } finally {
 311             acceptLock.unlock();
 312         }
 313     }
 314 
 315     @Override
 316     protected void implConfigureBlocking(boolean block) throws IOException {
 317         acceptLock.lock();
 318         try {
 319             synchronized (stateLock) {
 320                 ensureOpen();
 321                 IOUtil.configureBlocking(fd, block);
 322             }
 323         } finally {
 324             acceptLock.unlock();
 325         }
 326     }
 327 
 328     /**
 329      * Invoked by implCloseChannel to close the channel.
 330      *
 331      * This method waits for outstanding I/O operations to complete. When in
 332      * blocking mode, the socket is pre-closed and the threads in blocking I/O
 333      * operations are signalled to ensure that the outstanding I/O operations
 334      * complete quickly.
 335      *
 336      * The socket is closed by this method when it is not registered with a
 337      * Selector. Note that a channel configured blocking may be registered with
 338      * a Selector. This arises when a key is canceled and the channel configured
 339      * to blocking mode before the key is flushed from the Selector.
 340      */
 341     @Override
 342     protected void implCloseSelectableChannel() throws IOException {
 343         assert !isOpen();
 344 
 345         boolean interrupted = false;
 346         boolean blocking;
 347 
 348         // set state to ST_CLOSING
 349         synchronized (stateLock) {
 350             assert state < ST_CLOSING;
 351             state = ST_CLOSING;
 352             blocking = isBlocking();
 353         }
 354 
 355         // wait for any outstanding accept to complete
 356         if (blocking) {
 357             synchronized (stateLock) {
 358                 assert state == ST_CLOSING;
 359                 long th = thread;
 360                 if (th != 0) {
 361                     nd.preClose(fd);
 362                     NativeThread.signal(th);
 363 
 364                     // wait for accept operation to end
 365                     while (thread != 0) {
 366                         try {
 367                             stateLock.wait();
 368                         } catch (InterruptedException e) {
 369                             interrupted = true;
 370                         }
 371                     }
 372                 }
 373             }
 374         } else {
 375             // non-blocking mode: wait for accept to complete
 376             acceptLock.lock();
 377             acceptLock.unlock();
 378         }
 379 
 380         // set state to ST_KILLPENDING
 381         synchronized (stateLock) {
 382             assert state == ST_CLOSING;
 383             state = ST_KILLPENDING;
 384         }
 385 
 386         // close socket if not registered with Selector
 387         if (!isRegistered())
 388             kill();
 389 
 390         // restore interrupt status
 391         if (interrupted)
 392             Thread.currentThread().interrupt();
 393     }
 394 
 395     @Override
 396     public void kill() throws IOException {
 397         synchronized (stateLock) {
 398             if (state == ST_KILLPENDING) {
 399                 state = ST_KILLED;
 400                 nd.close(fd);
 401             }
 402         }
 403     }
 404 
 405     /**
 406      * Returns true if channel's socket is bound
 407      */
 408     boolean isBound() {
 409         synchronized (stateLock) {
 410             return localAddress != null;
 411         }
 412     }
 413 
 414     /**
 415      * Returns the local address, or null if not bound
 416      */
 417     InetSocketAddress localAddress() {
 418         synchronized (stateLock) {
 419             return localAddress;
 420         }
 421     }
 422 
 423     /**
 424      * Poll this channel's socket for a new connection up to the given timeout.
 425      * @return {@code true} if there is a connection to accept
 426      */
 427     boolean pollAccept(long timeout) throws IOException {
 428         assert Thread.holdsLock(blockingLock()) && isBlocking();
 429         acceptLock.lock();
 430         try {
 431             boolean polled = false;
 432             try {
 433                 begin(true);
 434                 int events = Net.poll(fd, Net.POLLIN, timeout);
 435                 polled = (events != 0);
 436             } finally {
 437                 end(true, polled);
 438             }
 439             return polled;
 440         } finally {
 441             acceptLock.unlock();
 442         }
 443     }
 444 
 445     /**
 446      * Translates native poll revent set into a ready operation set
 447      */
 448     public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
 449         int intOps = ski.nioInterestOps();
 450         int oldOps = ski.nioReadyOps();
 451         int newOps = initialOps;
 452 
 453         if ((ops & Net.POLLNVAL) != 0) {
 454             // This should only happen if this channel is pre-closed while a
 455             // selection operation is in progress
 456             // ## Throw an error if this channel has not been pre-closed
 457             return false;
 458         }
 459 
 460         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
 461             newOps = intOps;
 462             ski.nioReadyOps(newOps);
 463             return (newOps & ~oldOps) != 0;
 464         }
 465 
 466         if (((ops & Net.POLLIN) != 0) &&
 467             ((intOps & SelectionKey.OP_ACCEPT) != 0))
 468                 newOps |= SelectionKey.OP_ACCEPT;
 469 
 470         ski.nioReadyOps(newOps);
 471         return (newOps & ~oldOps) != 0;
 472     }
 473 
 474     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
 475         return translateReadyOps(ops, ski.nioReadyOps(), ski);
 476     }
 477 
 478     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
 479         return translateReadyOps(ops, 0, ski);
 480     }
 481 
 482     /**
 483      * Translates an interest operation set into a native poll event set
 484      */
 485     public int translateInterestOps(int ops) {
 486         int newOps = 0;
 487         if ((ops & SelectionKey.OP_ACCEPT) != 0)
 488             newOps |= Net.POLLIN;
 489         return newOps;
 490     }
 491 
 492     public FileDescriptor getFD() {
 493         return fd;
 494     }
 495 
 496     public int getFDVal() {
 497         return fdVal;
 498     }
 499 
 500     public String toString() {
 501         StringBuilder sb = new StringBuilder();
 502         sb.append(this.getClass().getName());
 503         sb.append('[');
 504         if (!isOpen()) {
 505             sb.append("closed");
 506         } else {
 507             synchronized (stateLock) {
 508                 InetSocketAddress addr = localAddress;
 509                 if (addr == null) {
 510                     sb.append("unbound");
 511                 } else {
 512                     sb.append(Net.getRevealedLocalAddressAsString(addr));
 513                 }
 514             }
 515         }
 516         sb.append(']');
 517         return sb.toString();
 518     }
 519 
 520     /**
 521      * Accept a connection on a socket.
 522      *
 523      * @implNote Wrap native call to allow instrumentation.
 524      */
 525     private int accept(FileDescriptor ssfd,
 526                        FileDescriptor newfd,
 527                        InetSocketAddress[] isaa)
 528         throws IOException
 529     {
 530         return accept0(ssfd, newfd, isaa);
 531     }
 532 
 533     // -- Native methods --
 534 
 535     // Accepts a new connection, setting the given file descriptor to refer to
 536     // the new socket and setting isaa[0] to the socket's remote address.
 537     // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no
 538     // connections are pending) or IOStatus.INTERRUPTED.
 539     //
 540     private native int accept0(FileDescriptor ssfd,
 541                                FileDescriptor newfd,
 542                                InetSocketAddress[] isaa)
 543         throws IOException;
 544 
 545     private static native void initIDs();
 546 
 547     static {
 548         IOUtil.load();
 549         initIDs();
 550         nd = new SocketDispatcher();
 551     }
 552 
 553 }