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 acceptLock.lock(); 214 try { 215 synchronized (stateLock) { 216 ensureOpen(); 217 if (localAddress != null) 218 throw new AlreadyBoundException(); 219 InetSocketAddress isa = (local == null) 220 ? new InetSocketAddress(0) 221 : Net.checkAddress(local); 222 SecurityManager sm = System.getSecurityManager(); 223 if (sm != null) 224 sm.checkListen(isa.getPort()); 225 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); 226 Net.bind(fd, isa.getAddress(), isa.getPort()); 227 Net.listen(fd, backlog < 1 ? 50 : backlog); 228 localAddress = Net.localAddress(fd); 229 } 230 } finally { 231 acceptLock.unlock(); 232 } 233 return this; 234 } 235 236 /** 237 * Marks the beginning of an I/O operation that might block. 238 * 239 * @throws ClosedChannelException if the channel is closed 240 * @throws NotYetBoundException if the channel's socket has not been bound yet 241 */ 242 private void begin(boolean blocking) throws ClosedChannelException { 243 if (blocking) 244 begin(); // set blocker to close channel if interrupted 245 synchronized (stateLock) { 246 ensureOpen(); 247 if (localAddress == null) 248 throw new NotYetBoundException(); 249 if (blocking) 250 thread = NativeThread.current(); 251 } 252 } 253 254 /** 255 * Marks the end of an I/O operation that may have blocked. 256 * 257 * @throws AsynchronousCloseException if the channel was closed due to this 258 * thread being interrupted on a blocking I/O operation. 259 */ 260 private void end(boolean blocking, boolean completed) 261 throws AsynchronousCloseException 262 { 263 if (blocking) { 264 synchronized (stateLock) { 265 thread = 0; 266 // notify any thread waiting in implCloseSelectableChannel 267 if (state == ST_CLOSING) { 268 stateLock.notifyAll(); 269 } 270 } 271 end(completed); 272 } 273 } 274 275 @Override 276 public SocketChannel accept() throws IOException { 277 acceptLock.lock(); 278 try { 279 int n = 0; 280 FileDescriptor newfd = new FileDescriptor(); 281 InetSocketAddress[] isaa = new InetSocketAddress[1]; 282 283 boolean blocking = isBlocking(); 284 try { 285 begin(blocking); 286 do { 287 n = accept(this.fd, newfd, isaa); 288 } while (n == IOStatus.INTERRUPTED && isOpen()); 289 } finally { 290 end(blocking, n > 0); 291 assert IOStatus.check(n); 292 } 293 294 if (n < 1) 295 return null; 296 297 // newly accepted socket is initially in blocking mode 298 IOUtil.configureBlocking(newfd, true); 299 300 InetSocketAddress isa = isaa[0]; 301 SocketChannel sc = new SocketChannelImpl(provider(), newfd, isa); 302 303 // check permitted to accept connections from the remote address 304 SecurityManager sm = System.getSecurityManager(); 305 if (sm != null) { 306 try { 307 sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort()); 308 } catch (SecurityException x) { 309 sc.close(); 310 throw x; 311 } 312 } 313 return sc; 314 315 } finally { 316 acceptLock.unlock(); 317 } 318 } 319 320 @Override 321 protected void implConfigureBlocking(boolean block) throws IOException { 322 acceptLock.lock(); 323 try { 324 synchronized (stateLock) { 325 ensureOpen(); 326 IOUtil.configureBlocking(fd, block); 327 } 328 } finally { 329 acceptLock.unlock(); 330 } 331 } 332 333 /** 334 * Invoked by implCloseChannel to close the channel. 335 * 336 * This method waits for outstanding I/O operations to complete. When in 337 * blocking mode, the socket is pre-closed and the threads in blocking I/O 338 * operations are signalled to ensure that the outstanding I/O operations 339 * complete quickly. 340 * 341 * The socket is closed by this method when it is not registered with a 342 * Selector. Note that a channel configured blocking may be registered with 343 * a Selector. This arises when a key is canceled and the channel configured 344 * to blocking mode before the key is flushed from the Selector. 345 */ 346 @Override 347 protected void implCloseSelectableChannel() throws IOException { 348 assert !isOpen(); 349 350 boolean interrupted = false; 351 boolean blocking; 352 353 // set state to ST_CLOSING 354 synchronized (stateLock) { 355 assert state < ST_CLOSING; 356 state = ST_CLOSING; 357 blocking = isBlocking(); 358 } 359 360 // wait for any outstanding accept to complete 361 if (blocking) { 362 synchronized (stateLock) { 363 assert state == ST_CLOSING; 364 long th = thread; 365 if (th != 0) { 366 nd.preClose(fd); 367 NativeThread.signal(th); 368 369 // wait for accept operation to end 370 while (thread != 0) { 371 try { 372 stateLock.wait(); 373 } catch (InterruptedException e) { 374 interrupted = true; 375 } 376 } 377 } 378 } 379 } else { 380 // non-blocking mode: wait for accept to complete 381 acceptLock.lock(); 382 acceptLock.unlock(); 383 } 384 385 // set state to ST_KILLPENDING 386 synchronized (stateLock) { 387 assert state == ST_CLOSING; 388 state = ST_KILLPENDING; 389 } 390 391 // close socket if not registered with Selector 392 if (!isRegistered()) 393 kill(); 394 395 // restore interrupt status 396 if (interrupted) 397 Thread.currentThread().interrupt(); 398 } 399 400 @Override 401 public void kill() throws IOException { 402 synchronized (stateLock) { 403 if (state == ST_KILLPENDING) { 404 state = ST_KILLED; 405 nd.close(fd); 406 } 407 } 408 } 409 410 /** 411 * Returns true if channel's socket is bound 412 */ 413 boolean isBound() { 414 synchronized (stateLock) { 415 return localAddress != null; 416 } 417 } 418 419 /** 420 * Returns the local address, or null if not bound 421 */ 422 InetSocketAddress localAddress() { 423 synchronized (stateLock) { 424 return localAddress; 425 } 426 } 427 428 /** 429 * Poll this channel's socket for a new connection up to the given timeout. 430 * @return {@code true} if there is a connection to accept 431 */ 432 boolean pollAccept(long timeout) throws IOException { 433 assert Thread.holdsLock(blockingLock()) && isBlocking(); 434 acceptLock.lock(); 435 try { 436 boolean polled = false; 437 try { 438 begin(true); 439 int n = Net.poll(fd, Net.POLLIN, timeout); 440 polled = (n > 0); 441 } finally { 442 end(true, polled); 443 } 444 return polled; 445 } finally { 446 acceptLock.unlock(); 447 } 448 } 449 450 /** 451 * Translates native poll revent set into a ready operation set 452 */ 453 public boolean translateReadyOps(int ops, int initialOps, 454 SelectionKeyImpl sk) { 455 int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes 456 int oldOps = sk.nioReadyOps(); 457 int newOps = initialOps; 458 459 if ((ops & Net.POLLNVAL) != 0) { 460 // This should only happen if this channel is pre-closed while a 461 // selection operation is in progress 462 // ## Throw an error if this channel has not been pre-closed 463 return false; 464 } 465 466 if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) { 467 newOps = intOps; 468 sk.nioReadyOps(newOps); 469 return (newOps & ~oldOps) != 0; 470 } 471 472 if (((ops & Net.POLLIN) != 0) && 473 ((intOps & SelectionKey.OP_ACCEPT) != 0)) 474 newOps |= SelectionKey.OP_ACCEPT; 475 476 sk.nioReadyOps(newOps); 477 return (newOps & ~oldOps) != 0; 478 } 479 480 public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) { 481 return translateReadyOps(ops, sk.nioReadyOps(), sk); 482 } 483 484 public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) { 485 return translateReadyOps(ops, 0, sk); 486 } 487 488 /** 489 * Translates an interest operation set into a native poll event set 490 */ 491 public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) { 492 int newOps = 0; 493 494 // Translate ops 495 if ((ops & SelectionKey.OP_ACCEPT) != 0) 496 newOps |= Net.POLLIN; 497 // Place ops into pollfd array 498 sk.selector.putEventOps(sk, 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 }