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