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