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