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