893N/A/*
2362N/A * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
893N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
893N/A *
893N/A * This code is free software; you can redistribute it and/or modify it
893N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
893N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
893N/A *
893N/A * This code is distributed in the hope that it will be useful, but WITHOUT
893N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
893N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
893N/A * version 2 for more details (a copy is included in the LICENSE file that
893N/A * accompanied this code).
893N/A *
893N/A * You should have received a copy of the GNU General Public License version
893N/A * 2 along with this work; if not, write to the Free Software Foundation,
893N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
893N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
893N/A */
893N/A
893N/Apackage sun.nio.ch;
893N/A
893N/Aimport java.nio.channels.*;
893N/Aimport java.net.InetSocketAddress;
893N/Aimport java.util.concurrent.Future;
893N/Aimport java.util.concurrent.atomic.AtomicBoolean;
893N/Aimport java.io.IOException;
893N/Aimport java.security.AccessControlContext;
893N/Aimport java.security.AccessController;
893N/Aimport java.security.PrivilegedAction;
893N/Aimport sun.misc.Unsafe;
893N/A
893N/A/**
893N/A * Windows implementation of AsynchronousServerSocketChannel using overlapped I/O.
893N/A */
893N/A
893N/Aclass WindowsAsynchronousServerSocketChannelImpl
893N/A extends AsynchronousServerSocketChannelImpl implements Iocp.OverlappedChannel
893N/A{
893N/A private static final Unsafe unsafe = Unsafe.getUnsafe();
893N/A
893N/A // 2 * (sizeof(SOCKET_ADDRESS) + 16)
893N/A private static final int DATA_BUFFER_SIZE = 88;
893N/A
893N/A private final long handle;
893N/A private final int completionKey;
893N/A private final Iocp iocp;
893N/A
893N/A // typically there will be zero, or one I/O operations pending. In rare
893N/A // cases there may be more. These rare cases arise when a sequence of accept
893N/A // operations complete immediately and handled by the initiating thread.
893N/A // The corresponding OVERLAPPED cannot be reused/released until the completion
893N/A // event has been posted.
893N/A private final PendingIoCache ioCache;
893N/A
893N/A // the data buffer to receive the local/remote socket address
893N/A private final long dataBuffer;
893N/A
893N/A // flag to indicate that an accept operation is outstanding
893N/A private AtomicBoolean accepting = new AtomicBoolean();
893N/A
893N/A
893N/A WindowsAsynchronousServerSocketChannelImpl(Iocp iocp) throws IOException {
893N/A super(iocp);
893N/A
893N/A // associate socket with given completion port
893N/A long h = IOUtil.fdVal(fd);
893N/A int key;
893N/A try {
893N/A key = iocp.associate(this, h);
893N/A } catch (IOException x) {
893N/A closesocket0(h); // prevent leak
893N/A throw x;
893N/A }
893N/A
893N/A this.handle = h;
893N/A this.completionKey = key;
893N/A this.iocp = iocp;
893N/A this.ioCache = new PendingIoCache();
893N/A this.dataBuffer = unsafe.allocateMemory(DATA_BUFFER_SIZE);
893N/A }
893N/A
893N/A @Override
893N/A public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
893N/A return ioCache.remove(overlapped);
893N/A }
893N/A
893N/A @Override
893N/A void implClose() throws IOException {
893N/A // close socket (which may cause outstanding accept to be aborted).
893N/A closesocket0(handle);
893N/A
893N/A // waits until the accept operations have completed
893N/A ioCache.close();
893N/A
893N/A // finally disassociate from the completion port
893N/A iocp.disassociate(completionKey);
893N/A
893N/A // release other resources
893N/A unsafe.freeMemory(dataBuffer);
893N/A }
893N/A
893N/A @Override
893N/A public AsynchronousChannelGroupImpl group() {
893N/A return iocp;
893N/A }
893N/A
893N/A /**
893N/A * Task to initiate accept operation and to handle result.
893N/A */
1580N/A private class AcceptTask implements Runnable, Iocp.ResultHandler {
893N/A private final WindowsAsynchronousSocketChannelImpl channel;
893N/A private final AccessControlContext acc;
1580N/A private final PendingFuture<AsynchronousSocketChannel,Object> result;
893N/A
893N/A AcceptTask(WindowsAsynchronousSocketChannelImpl channel,
893N/A AccessControlContext acc,
1580N/A PendingFuture<AsynchronousSocketChannel,Object> result)
893N/A {
893N/A this.channel = channel;
893N/A this.acc = acc;
893N/A this.result = result;
893N/A }
893N/A
893N/A void enableAccept() {
893N/A accepting.set(false);
893N/A }
893N/A
893N/A void closeChildChannel() {
893N/A try {
893N/A channel.close();
893N/A } catch (IOException ignore) { }
893N/A }
893N/A
893N/A // caller must have acquired read lock for the listener and child channel.
893N/A void finishAccept() throws IOException {
893N/A /**
893N/A * Set local/remote addresses. This is currently very inefficient
893N/A * in that it requires 2 calls to getsockname and 2 calls to getpeername.
893N/A * (should change this to use GetAcceptExSockaddrs)
893N/A */
893N/A updateAcceptContext(handle, channel.handle());
893N/A
893N/A InetSocketAddress local = Net.localAddress(channel.fd);
893N/A final InetSocketAddress remote = Net.remoteAddress(channel.fd);
893N/A channel.setConnected(local, remote);
893N/A
893N/A // permission check (in context of initiating thread)
893N/A if (acc != null) {
893N/A AccessController.doPrivileged(new PrivilegedAction<Void>() {
893N/A public Void run() {
893N/A SecurityManager sm = System.getSecurityManager();
893N/A sm.checkAccept(remote.getAddress().getHostAddress(),
893N/A remote.getPort());
893N/A return null;
893N/A }
893N/A }, acc);
893N/A }
893N/A }
893N/A
893N/A /**
893N/A * Initiates the accept operation.
893N/A */
893N/A @Override
893N/A public void run() {
893N/A long overlapped = 0L;
893N/A
893N/A try {
893N/A // begin usage of listener socket
893N/A begin();
893N/A try {
893N/A // begin usage of child socket (as it is registered with
893N/A // completion port and so may be closed in the event that
893N/A // the group is forcefully closed).
893N/A channel.begin();
893N/A
893N/A synchronized (result) {
893N/A overlapped = ioCache.add(result);
893N/A
893N/A int n = accept0(handle, channel.handle(), overlapped, dataBuffer);
893N/A if (n == IOStatus.UNAVAILABLE) {
893N/A return;
893N/A }
893N/A
893N/A // connection accepted immediately
893N/A finishAccept();
893N/A
893N/A // allow another accept before the result is set
893N/A enableAccept();
893N/A result.setResult(channel);
893N/A }
893N/A } finally {
893N/A // end usage on child socket
893N/A channel.end();
893N/A }
893N/A } catch (Throwable x) {
893N/A // failed to initiate accept so release resources
893N/A if (overlapped != 0L)
893N/A ioCache.remove(overlapped);
893N/A closeChildChannel();
893N/A if (x instanceof ClosedChannelException)
893N/A x = new AsynchronousCloseException();
893N/A if (!(x instanceof IOException) && !(x instanceof SecurityException))
893N/A x = new IOException(x);
893N/A enableAccept();
893N/A result.setFailure(x);
893N/A } finally {
893N/A // end of usage of listener socket
893N/A end();
893N/A }
893N/A
893N/A // accept completed immediately but may not have executed on
893N/A // initiating thread in which case the operation may have been
893N/A // cancelled.
893N/A if (result.isCancelled()) {
893N/A closeChildChannel();
893N/A }
893N/A
893N/A // invoke completion handler
1580N/A Invoker.invokeIndirectly(result);
893N/A }
893N/A
893N/A /**
893N/A * Executed when the I/O has completed
893N/A */
893N/A @Override
1580N/A public void completed(int bytesTransferred, boolean canInvokeDirect) {
893N/A try {
893N/A // connection accept after group has shutdown
893N/A if (iocp.isShutdown()) {
893N/A throw new IOException(new ShutdownChannelGroupException());
893N/A }
893N/A
893N/A // finish the accept
893N/A try {
893N/A begin();
893N/A try {
893N/A channel.begin();
893N/A finishAccept();
893N/A } finally {
893N/A channel.end();
893N/A }
893N/A } finally {
893N/A end();
893N/A }
893N/A
893N/A // allow another accept before the result is set
893N/A enableAccept();
893N/A result.setResult(channel);
893N/A } catch (Throwable x) {
893N/A enableAccept();
893N/A closeChildChannel();
893N/A if (x instanceof ClosedChannelException)
893N/A x = new AsynchronousCloseException();
893N/A if (!(x instanceof IOException) && !(x instanceof SecurityException))
893N/A x = new IOException(x);
893N/A result.setFailure(x);
893N/A }
893N/A
893N/A // if an async cancel has already cancelled the operation then
893N/A // close the new channel so as to free resources
893N/A if (result.isCancelled()) {
893N/A closeChildChannel();
893N/A }
893N/A
893N/A // invoke handler (but not directly)
1580N/A Invoker.invokeIndirectly(result);
893N/A }
893N/A
893N/A @Override
893N/A public void failed(int error, IOException x) {
893N/A enableAccept();
893N/A closeChildChannel();
893N/A
893N/A // release waiters
893N/A if (isOpen()) {
893N/A result.setFailure(x);
893N/A } else {
893N/A result.setFailure(new AsynchronousCloseException());
893N/A }
1580N/A Invoker.invokeIndirectly(result);
893N/A }
893N/A }
893N/A
893N/A @Override
1580N/A Future<AsynchronousSocketChannel> implAccept(Object attachment,
1580N/A final CompletionHandler<AsynchronousSocketChannel,Object> handler)
893N/A {
893N/A if (!isOpen()) {
1580N/A Throwable exc = new ClosedChannelException();
1580N/A if (handler == null)
1580N/A return CompletedFuture.withFailure(exc);
1580N/A Invoker.invokeIndirectly(this, handler, attachment, null, exc);
1580N/A return null;
893N/A }
893N/A if (isAcceptKilled())
893N/A throw new RuntimeException("Accept not allowed due to cancellation");
893N/A
893N/A // ensure channel is bound to local address
893N/A if (localAddress == null)
893N/A throw new NotYetBoundException();
893N/A
893N/A // create the socket that will be accepted. The creation of the socket
893N/A // is enclosed by a begin/end for the listener socket to ensure that
893N/A // we check that the listener is open and also to prevent the I/O
893N/A // port from being closed as the new socket is registered.
893N/A WindowsAsynchronousSocketChannelImpl ch = null;
893N/A IOException ioe = null;
893N/A try {
893N/A begin();
893N/A ch = new WindowsAsynchronousSocketChannelImpl(iocp, false);
893N/A } catch (IOException x) {
893N/A ioe = x;
893N/A } finally {
893N/A end();
893N/A }
893N/A if (ioe != null) {
1580N/A if (handler == null)
1580N/A return CompletedFuture.withFailure(ioe);
1580N/A Invoker.invokeIndirectly(this, handler, attachment, null, ioe);
1580N/A return null;
893N/A }
893N/A
893N/A // need calling context when there is security manager as
893N/A // permission check may be done in a different thread without
893N/A // any application call frames on the stack
893N/A AccessControlContext acc = (System.getSecurityManager() == null) ?
893N/A null : AccessController.getContext();
893N/A
1580N/A PendingFuture<AsynchronousSocketChannel,Object> result =
1580N/A new PendingFuture<AsynchronousSocketChannel,Object>(this, handler, attachment);
1580N/A AcceptTask task = new AcceptTask(ch, acc, result);
893N/A result.setContext(task);
893N/A
893N/A // check and set flag to prevent concurrent accepting
893N/A if (!accepting.compareAndSet(false, true))
893N/A throw new AcceptPendingException();
893N/A
1580N/A // initiate I/O
1580N/A if (Iocp.supportsThreadAgnosticIo()) {
1580N/A task.run();
1580N/A } else {
1580N/A Invoker.invokeOnThreadInThreadPool(this, task);
1580N/A }
893N/A return result;
893N/A }
893N/A
893N/A // -- Native methods --
893N/A
893N/A private static native void initIDs();
893N/A
893N/A private static native int accept0(long listenSocket, long acceptSocket,
893N/A long overlapped, long dataBuffer) throws IOException;
893N/A
893N/A private static native void updateAcceptContext(long listenSocket,
893N/A long acceptSocket) throws IOException;
893N/A
893N/A private static native void closesocket0(long socket) throws IOException;
893N/A
893N/A static {
893N/A Util.load();
893N/A initIDs();
893N/A }
893N/A}