Path: blob/master/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java
41139 views
/*1* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.ch;2627import java.nio.channels.*;28import java.net.InetSocketAddress;29import java.util.concurrent.Future;30import java.util.concurrent.atomic.AtomicBoolean;31import java.io.IOException;32import java.security.AccessControlContext;33import java.security.AccessController;34import java.security.PrivilegedAction;35import jdk.internal.misc.Unsafe;3637/**38* Windows implementation of AsynchronousServerSocketChannel using overlapped I/O.39*/4041class WindowsAsynchronousServerSocketChannelImpl42extends AsynchronousServerSocketChannelImpl implements Iocp.OverlappedChannel43{44private static final Unsafe unsafe = Unsafe.getUnsafe();4546// 2 * (sizeof(SOCKET_ADDRESS) + 16)47private static final int DATA_BUFFER_SIZE = 88;4849private final long handle;50private final int completionKey;51private final Iocp iocp;5253// typically there will be zero, or one I/O operations pending. In rare54// cases there may be more. These rare cases arise when a sequence of accept55// operations complete immediately and handled by the initiating thread.56// The corresponding OVERLAPPED cannot be reused/released until the completion57// event has been posted.58private final PendingIoCache ioCache;5960// the data buffer to receive the local/remote socket address61private final long dataBuffer;6263// flag to indicate that an accept operation is outstanding64private AtomicBoolean accepting = new AtomicBoolean();656667WindowsAsynchronousServerSocketChannelImpl(Iocp iocp) throws IOException {68super(iocp);6970// associate socket with given completion port71long h = IOUtil.fdVal(fd);72int key;73try {74key = iocp.associate(this, h);75} catch (IOException x) {76closesocket0(h); // prevent leak77throw x;78}7980this.handle = h;81this.completionKey = key;82this.iocp = iocp;83this.ioCache = new PendingIoCache();84this.dataBuffer = unsafe.allocateMemory(DATA_BUFFER_SIZE);85}8687@Override88public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {89return ioCache.remove(overlapped);90}9192@Override93void implClose() throws IOException {94// close socket (which may cause outstanding accept to be aborted).95closesocket0(handle);9697// waits until the accept operations have completed98ioCache.close();99100// finally disassociate from the completion port101iocp.disassociate(completionKey);102103// release other resources104unsafe.freeMemory(dataBuffer);105}106107@Override108public AsynchronousChannelGroupImpl group() {109return iocp;110}111112/**113* Task to initiate accept operation and to handle result.114*/115private class AcceptTask implements Runnable, Iocp.ResultHandler {116private final WindowsAsynchronousSocketChannelImpl channel;117@SuppressWarnings("removal")118private final AccessControlContext acc;119private final PendingFuture<AsynchronousSocketChannel,Object> result;120121AcceptTask(WindowsAsynchronousSocketChannelImpl channel,122@SuppressWarnings("removal") AccessControlContext acc,123PendingFuture<AsynchronousSocketChannel,Object> result)124{125this.channel = channel;126this.acc = acc;127this.result = result;128}129130void enableAccept() {131accepting.set(false);132}133134void closeChildChannel() {135try {136channel.close();137} catch (IOException ignore) { }138}139140// caller must have acquired read lock for the listener and child channel.141@SuppressWarnings("removal")142void finishAccept() throws IOException {143/**144* Set local/remote addresses. This is currently very inefficient145* in that it requires 2 calls to getsockname and 2 calls to getpeername.146* (should change this to use GetAcceptExSockaddrs)147*/148updateAcceptContext(handle, channel.handle());149150InetSocketAddress local = Net.localAddress(channel.fd);151final InetSocketAddress remote = Net.remoteAddress(channel.fd);152channel.setConnected(local, remote);153154// permission check (in context of initiating thread)155if (acc != null) {156AccessController.doPrivileged(new PrivilegedAction<Void>() {157public Void run() {158SecurityManager sm = System.getSecurityManager();159sm.checkAccept(remote.getAddress().getHostAddress(),160remote.getPort());161return null;162}163}, acc);164}165}166167/**168* Initiates the accept operation.169*/170@Override171public void run() {172long overlapped = 0L;173174try {175// begin usage of listener socket176begin();177try {178// begin usage of child socket (as it is registered with179// completion port and so may be closed in the event that180// the group is forcefully closed).181channel.begin();182183synchronized (result) {184overlapped = ioCache.add(result);185186int n = accept0(handle, channel.handle(), overlapped, dataBuffer);187if (n == IOStatus.UNAVAILABLE) {188return;189}190191// connection accepted immediately192finishAccept();193194// allow another accept before the result is set195enableAccept();196result.setResult(channel);197}198} finally {199// end usage on child socket200channel.end();201}202} catch (Throwable x) {203// failed to initiate accept so release resources204if (overlapped != 0L)205ioCache.remove(overlapped);206closeChildChannel();207if (x instanceof ClosedChannelException)208x = new AsynchronousCloseException();209if (!(x instanceof IOException) && !(x instanceof SecurityException))210x = new IOException(x);211enableAccept();212result.setFailure(x);213} finally {214// end of usage of listener socket215end();216}217218// accept completed immediately but may not have executed on219// initiating thread in which case the operation may have been220// cancelled.221if (result.isCancelled()) {222closeChildChannel();223}224225// invoke completion handler226Invoker.invokeIndirectly(result);227}228229/**230* Executed when the I/O has completed231*/232@Override233public void completed(int bytesTransferred, boolean canInvokeDirect) {234try {235// connection accept after group has shutdown236if (iocp.isShutdown()) {237throw new IOException(new ShutdownChannelGroupException());238}239240// finish the accept241try {242begin();243try {244channel.begin();245finishAccept();246} finally {247channel.end();248}249} finally {250end();251}252253// allow another accept before the result is set254enableAccept();255result.setResult(channel);256} catch (Throwable x) {257enableAccept();258closeChildChannel();259if (x instanceof ClosedChannelException)260x = new AsynchronousCloseException();261if (!(x instanceof IOException) && !(x instanceof SecurityException))262x = new IOException(x);263result.setFailure(x);264}265266// if an async cancel has already cancelled the operation then267// close the new channel so as to free resources268if (result.isCancelled()) {269closeChildChannel();270}271272// invoke handler (but not directly)273Invoker.invokeIndirectly(result);274}275276@Override277public void failed(int error, IOException x) {278enableAccept();279closeChildChannel();280281// release waiters282if (isOpen()) {283result.setFailure(x);284} else {285result.setFailure(new AsynchronousCloseException());286}287Invoker.invokeIndirectly(result);288}289}290291@Override292Future<AsynchronousSocketChannel> implAccept(Object attachment,293final CompletionHandler<AsynchronousSocketChannel,Object> handler)294{295if (!isOpen()) {296Throwable exc = new ClosedChannelException();297if (handler == null)298return CompletedFuture.withFailure(exc);299Invoker.invokeIndirectly(this, handler, attachment, null, exc);300return null;301}302if (isAcceptKilled())303throw new RuntimeException("Accept not allowed due to cancellation");304305// ensure channel is bound to local address306if (localAddress == null)307throw new NotYetBoundException();308309// create the socket that will be accepted. The creation of the socket310// is enclosed by a begin/end for the listener socket to ensure that311// we check that the listener is open and also to prevent the I/O312// port from being closed as the new socket is registered.313WindowsAsynchronousSocketChannelImpl ch = null;314IOException ioe = null;315try {316begin();317ch = new WindowsAsynchronousSocketChannelImpl(iocp, false);318} catch (IOException x) {319ioe = x;320} finally {321end();322}323if (ioe != null) {324if (handler == null)325return CompletedFuture.withFailure(ioe);326Invoker.invokeIndirectly(this, handler, attachment, null, ioe);327return null;328}329330// need calling context when there is security manager as331// permission check may be done in a different thread without332// any application call frames on the stack333@SuppressWarnings("removal")334AccessControlContext acc = (System.getSecurityManager() == null) ?335null : AccessController.getContext();336337PendingFuture<AsynchronousSocketChannel,Object> result =338new PendingFuture<AsynchronousSocketChannel,Object>(this, handler, attachment);339AcceptTask task = new AcceptTask(ch, acc, result);340result.setContext(task);341342// check and set flag to prevent concurrent accepting343if (!accepting.compareAndSet(false, true))344throw new AcceptPendingException();345346// initiate I/O347task.run();348return result;349}350351// -- Native methods --352353private static native void initIDs();354355private static native int accept0(long listenSocket, long acceptSocket,356long overlapped, long dataBuffer) throws IOException;357358private static native void updateAcceptContext(long listenSocket,359long acceptSocket) throws IOException;360361private static native void closesocket0(long socket) throws IOException;362363static {364IOUtil.load();365initIDs();366}367}368369370