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 }