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