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