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.ClosedChannelException; 39 import java.nio.channels.NotYetBoundException; 40 import java.nio.channels.SelectionKey; 41 import java.nio.channels.ServerSocketChannel; 42 import java.nio.channels.SocketChannel; 43 import java.nio.channels.spi.SelectorProvider; 44 import java.util.Collections; 45 import java.util.HashSet; 46 import java.util.Set; 47 import java.util.concurrent.locks.ReentrantLock; 48 49 import sun.net.NetHooks; 50 51 /** 52 * An implementation of ServerSocketChannels 53 */ 54 55 class ServerSocketChannelImpl 56 extends ServerSocketChannel 57 implements SelChImpl 58 { 59 60 // Used to make native close and configure calls 61 private static NativeDispatcher nd; 62 63 // Our file descriptor 64 private final FileDescriptor fd; 65 66 // fd value needed for dev/poll. This value will remain valid 67 // even after the value in the file descriptor object has been set to -1 68 private int fdVal; 69 70 // ID of native thread currently blocked in this channel, for signalling 71 private volatile long thread; 72 73 // Lock held by thread currently blocked in this channel 74 private final ReentrantLock acceptLock = new ReentrantLock(); 75 76 // Lock held by any thread that modifies the state fields declared below 77 // DO NOT invoke a blocking I/O operation while holding this lock! 78 private final Object stateLock = new Object(); 79 80 // -- The following fields are protected by stateLock 81 82 // Channel state, increases monotonically 83 private static final int ST_UNINITIALIZED = -1; 84 private static final int ST_INUSE = 0; 85 private static final int ST_KILLED = 1; 86 private int state = ST_UNINITIALIZED; 87 88 // Binding 89 private InetSocketAddress localAddress; // null => unbound 90 91 // set true when exclusive binding is on and SO_REUSEADDR is emulated 92 private boolean isReuseAddress; 93 94 // Our socket adaptor, if any 95 private ServerSocket socket; 96 97 // -- End of fields protected by stateLock 98 99 100 ServerSocketChannelImpl(SelectorProvider sp) throws IOException { 101 super(sp); 102 this.fd = Net.serverSocket(true); 103 this.fdVal = IOUtil.fdVal(fd); 104 this.state = ST_INUSE; 105 } 106 107 ServerSocketChannelImpl(SelectorProvider sp, 108 FileDescriptor fd, 109 boolean bound) 110 throws IOException 111 { 112 super(sp); 113 this.fd = fd; 114 this.fdVal = IOUtil.fdVal(fd); 115 this.state = ST_INUSE; 116 if (bound) 117 localAddress = Net.localAddress(fd); 118 } 119 120 public ServerSocket socket() { 121 synchronized (stateLock) { 122 if (socket == null) 123 socket = ServerSocketAdaptor.create(this); 124 return socket; 125 } 126 } 127 128 @Override 129 public SocketAddress getLocalAddress() throws IOException { 130 synchronized (stateLock) { 131 if (!isOpen()) 132 throw new ClosedChannelException(); 133 return localAddress == null ? localAddress 134 : Net.getRevealedLocalAddress( 135 Net.asInetSocketAddress(localAddress)); 136 } 137 } 138 139 @Override 140 public <T> ServerSocketChannel setOption(SocketOption<T> name, T value) 141 throws IOException 142 { 143 if (name == null) 144 throw new NullPointerException(); 145 if (!supportedOptions().contains(name)) 146 throw new UnsupportedOperationException("'" + name + "' not supported"); 147 synchronized (stateLock) { 148 if (!isOpen()) 149 throw new ClosedChannelException(); 150 151 if (name == StandardSocketOptions.IP_TOS) { 152 ProtocolFamily family = Net.isIPv6Available() ? 153 StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; 154 Net.setSocketOption(fd, family, name, value); 155 return this; 156 } 157 158 if (name == StandardSocketOptions.SO_REUSEADDR && 159 Net.useExclusiveBind()) 160 { 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 if (name == null) 177 throw new NullPointerException(); 178 if (!supportedOptions().contains(name)) 179 throw new UnsupportedOperationException("'" + name + "' not supported"); 180 181 synchronized (stateLock) { 182 if (!isOpen()) 183 throw new ClosedChannelException(); 184 if (name == StandardSocketOptions.SO_REUSEADDR && 185 Net.useExclusiveBind()) 186 { 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<>(2); 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.add(StandardSocketOptions.IP_TOS); 206 return Collections.unmodifiableSet(set); 207 } 208 } 209 210 @Override 211 public final Set<SocketOption<?>> supportedOptions() { 212 return DefaultOptionsHolder.defaultOptions; 213 } 214 215 public boolean isBound() { 216 synchronized (stateLock) { 217 return localAddress != null; 218 } 219 } 220 221 public InetSocketAddress localAddress() { 222 synchronized (stateLock) { 223 return localAddress; 224 } 225 } 226 227 @Override 228 public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { 229 acceptLock.lock(); 230 try { 231 if (!isOpen()) 232 throw new ClosedChannelException(); 233 if (isBound()) 234 throw new AlreadyBoundException(); 235 InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : 236 Net.checkAddress(local); 237 SecurityManager sm = System.getSecurityManager(); 238 if (sm != null) 239 sm.checkListen(isa.getPort()); 240 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); 241 Net.bind(fd, isa.getAddress(), isa.getPort()); 242 Net.listen(fd, backlog < 1 ? 50 : backlog); 243 synchronized (stateLock) { 244 localAddress = Net.localAddress(fd); 245 } 246 } finally { 247 acceptLock.unlock(); 248 } 249 return this; 250 } 251 252 public SocketChannel accept() throws IOException { 253 acceptLock.lock(); 254 try { 255 if (!isOpen()) 256 throw new ClosedChannelException(); 257 if (!isBound()) 258 throw new NotYetBoundException(); 259 SocketChannel sc = null; 260 261 int n = 0; 262 FileDescriptor newfd = new FileDescriptor(); 263 InetSocketAddress[] isaa = new InetSocketAddress[1]; 264 265 try { 266 begin(); 267 if (!isOpen()) 268 return null; 269 thread = NativeThread.current(); 270 for (;;) { 271 n = accept(this.fd, newfd, isaa); 272 if ((n == IOStatus.INTERRUPTED) && isOpen()) 273 continue; 274 break; 275 } 276 } finally { 277 thread = 0; 278 end(n > 0); 279 assert IOStatus.check(n); 280 } 281 282 if (n < 1) 283 return null; 284 285 IOUtil.configureBlocking(newfd, true); 286 InetSocketAddress isa = isaa[0]; 287 sc = new SocketChannelImpl(provider(), newfd, isa); 288 SecurityManager sm = System.getSecurityManager(); 289 if (sm != null) { 290 try { 291 sm.checkAccept(isa.getAddress().getHostAddress(), 292 isa.getPort()); 293 } catch (SecurityException x) { 294 sc.close(); 295 throw x; 296 } 297 } 298 return sc; 299 300 } finally { 301 acceptLock.unlock(); 302 } 303 } 304 305 protected void implConfigureBlocking(boolean block) throws IOException { 306 IOUtil.configureBlocking(fd, block); 307 } 308 309 protected void implCloseSelectableChannel() throws IOException { 310 synchronized (stateLock) { 311 if (state != ST_KILLED) 312 nd.preClose(fd); 313 long th = thread; 314 if (th != 0) 315 NativeThread.signal(th); 316 if (!isRegistered()) 317 kill(); 318 } 319 } 320 321 public void kill() throws IOException { 322 synchronized (stateLock) { 323 if (state == ST_KILLED) 324 return; 325 if (state == ST_UNINITIALIZED) { 326 state = ST_KILLED; 327 return; 328 } 329 assert !isOpen() && !isRegistered(); 330 nd.close(fd); 331 state = ST_KILLED; 332 } 333 } 334 335 /** 336 * Translates native poll revent set into a ready operation set 337 */ 338 public boolean translateReadyOps(int ops, int initialOps, 339 SelectionKeyImpl sk) { 340 int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes 341 int oldOps = sk.nioReadyOps(); 342 int newOps = initialOps; 343 344 if ((ops & Net.POLLNVAL) != 0) { 345 // This should only happen if this channel is pre-closed while a 346 // selection operation is in progress 347 // ## Throw an error if this channel has not been pre-closed 348 return false; 349 } 350 351 if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) { 352 newOps = intOps; 353 sk.nioReadyOps(newOps); 354 return (newOps & ~oldOps) != 0; 355 } 356 357 if (((ops & Net.POLLIN) != 0) && 358 ((intOps & SelectionKey.OP_ACCEPT) != 0)) 359 newOps |= SelectionKey.OP_ACCEPT; 360 361 sk.nioReadyOps(newOps); 362 return (newOps & ~oldOps) != 0; 363 } 364 365 public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) { 366 return translateReadyOps(ops, sk.nioReadyOps(), sk); 367 } 368 369 public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) { 370 return translateReadyOps(ops, 0, sk); 371 } 372 373 // package-private 374 int poll(int events, long timeout) throws IOException { 375 assert Thread.holdsLock(blockingLock()) && !isBlocking(); 376 377 acceptLock.lock(); 378 try { 379 int n = 0; 380 try { 381 begin(); 382 synchronized (stateLock) { 383 if (!isOpen()) 384 return 0; 385 thread = NativeThread.current(); 386 } 387 n = Net.poll(fd, events, timeout); 388 } finally { 389 thread = 0; 390 end(n > 0); 391 } 392 return n; 393 } finally { 394 acceptLock.unlock(); 395 } 396 } 397 398 /** 399 * Translates an interest operation set into a native poll event set 400 */ 401 public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) { 402 int newOps = 0; 403 404 // Translate ops 405 if ((ops & SelectionKey.OP_ACCEPT) != 0) 406 newOps |= Net.POLLIN; 407 // Place ops into pollfd array 408 sk.selector.putEventOps(sk, newOps); 409 } 410 411 public FileDescriptor getFD() { 412 return fd; 413 } 414 415 public int getFDVal() { 416 return fdVal; 417 } 418 419 public String toString() { 420 StringBuilder sb = new StringBuilder(); 421 sb.append(this.getClass().getName()); 422 sb.append('['); 423 if (!isOpen()) { 424 sb.append("closed"); 425 } else { 426 synchronized (stateLock) { 427 InetSocketAddress addr = localAddress(); 428 if (addr == null) { 429 sb.append("unbound"); 430 } else { 431 sb.append(Net.getRevealedLocalAddressAsString(addr)); 432 } 433 } 434 } 435 sb.append(']'); 436 return sb.toString(); 437 } 438 439 /** 440 * Accept a connection on a socket. 441 * 442 * @implNote Wrap native call to allow instrumentation. 443 */ 444 private int accept(FileDescriptor ssfd, FileDescriptor newfd, 445 InetSocketAddress[] isaa) 446 throws IOException 447 { 448 return accept0(ssfd, newfd, isaa); 449 } 450 451 // -- Native methods -- 452 453 // Accepts a new connection, setting the given file descriptor to refer to 454 // the new socket and setting isaa[0] to the socket's remote address. 455 // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no 456 // connections are pending) or IOStatus.INTERRUPTED. 457 // 458 private native int accept0(FileDescriptor ssfd, FileDescriptor newfd, 459 InetSocketAddress[] isaa) 460 throws IOException; 461 462 private static native void initIDs(); 463 464 static { 465 IOUtil.load(); 466 initIDs(); 467 nd = new SocketDispatcher(); 468 } 469 470 }