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