0N/A/*
4963N/A * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/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
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/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.
0N/A */
0N/A
0N/Apackage sun.nio.ch;
0N/A
0N/Aimport java.io.FileDescriptor;
0N/Aimport java.io.IOException;
0N/Aimport java.net.*;
0N/Aimport java.nio.ByteBuffer;
0N/Aimport java.nio.channels.*;
0N/Aimport java.nio.channels.spi.*;
524N/Aimport java.util.*;
1040N/Aimport sun.net.NetHooks;
5503N/Aimport sun.misc.IoTrace;
0N/A
0N/A/**
0N/A * An implementation of SocketChannels
0N/A */
0N/A
0N/Aclass SocketChannelImpl
0N/A extends SocketChannel
0N/A implements SelChImpl
0N/A{
0N/A
0N/A // Used to make native read and write calls
0N/A private static NativeDispatcher nd;
0N/A
0N/A // Our file descriptor object
0N/A private final FileDescriptor fd;
0N/A
0N/A // fd value needed for dev/poll. This value will remain valid
0N/A // even after the value in the file descriptor object has been set to -1
0N/A private final int fdVal;
0N/A
0N/A // IDs of native threads doing reads and writes, for signalling
0N/A private volatile long readerThread = 0;
0N/A private volatile long writerThread = 0;
0N/A
0N/A // Lock held by current reading or connecting thread
0N/A private final Object readLock = new Object();
0N/A
0N/A // Lock held by current writing or connecting thread
0N/A private final Object writeLock = new Object();
0N/A
0N/A // Lock held by any thread that modifies the state fields declared below
0N/A // DO NOT invoke a blocking I/O operation while holding this lock!
0N/A private final Object stateLock = new Object();
0N/A
0N/A // -- The following fields are protected by stateLock
0N/A
6272N/A // set true when exclusive binding is on and SO_REUSEADDR is emulated
6272N/A private boolean isReuseAddress;
6272N/A
0N/A // State, increases monotonically
0N/A private static final int ST_UNINITIALIZED = -1;
0N/A private static final int ST_UNCONNECTED = 0;
0N/A private static final int ST_PENDING = 1;
0N/A private static final int ST_CONNECTED = 2;
0N/A private static final int ST_KILLPENDING = 3;
0N/A private static final int ST_KILLED = 4;
0N/A private int state = ST_UNINITIALIZED;
0N/A
0N/A // Binding
6319N/A private InetSocketAddress localAddress;
6319N/A private InetSocketAddress remoteAddress;
0N/A
0N/A // Input/Output open
0N/A private boolean isInputOpen = true;
0N/A private boolean isOutputOpen = true;
0N/A private boolean readyToConnect = false;
0N/A
0N/A // Socket adaptor, created on demand
524N/A private Socket socket;
0N/A
0N/A // -- End of fields protected by stateLock
0N/A
0N/A
0N/A // Constructor for normal connecting sockets
0N/A //
0N/A SocketChannelImpl(SelectorProvider sp) throws IOException {
0N/A super(sp);
0N/A this.fd = Net.socket(true);
0N/A this.fdVal = IOUtil.fdVal(fd);
0N/A this.state = ST_UNCONNECTED;
0N/A }
0N/A
2736N/A SocketChannelImpl(SelectorProvider sp,
2736N/A FileDescriptor fd,
2736N/A boolean bound)
2736N/A throws IOException
2736N/A {
2736N/A super(sp);
2736N/A this.fd = fd;
2736N/A this.fdVal = IOUtil.fdVal(fd);
2736N/A this.state = ST_UNCONNECTED;
2736N/A if (bound)
2736N/A this.localAddress = Net.localAddress(fd);
2736N/A }
2736N/A
0N/A // Constructor for sockets obtained from server sockets
0N/A //
0N/A SocketChannelImpl(SelectorProvider sp,
0N/A FileDescriptor fd, InetSocketAddress remote)
0N/A throws IOException
0N/A {
0N/A super(sp);
0N/A this.fd = fd;
0N/A this.fdVal = IOUtil.fdVal(fd);
0N/A this.state = ST_CONNECTED;
524N/A this.localAddress = Net.localAddress(fd);
0N/A this.remoteAddress = remote;
0N/A }
0N/A
0N/A public Socket socket() {
0N/A synchronized (stateLock) {
0N/A if (socket == null)
0N/A socket = SocketAdaptor.create(this);
0N/A return socket;
0N/A }
0N/A }
0N/A
524N/A @Override
524N/A public SocketAddress getLocalAddress() throws IOException {
524N/A synchronized (stateLock) {
524N/A if (!isOpen())
893N/A throw new ClosedChannelException();
6319N/A return Net.getRevealedLocalAddress(localAddress);
524N/A }
524N/A }
524N/A
524N/A @Override
893N/A public SocketAddress getRemoteAddress() throws IOException {
524N/A synchronized (stateLock) {
524N/A if (!isOpen())
893N/A throw new ClosedChannelException();
524N/A return remoteAddress;
524N/A }
524N/A }
524N/A
524N/A @Override
893N/A public <T> SocketChannel setOption(SocketOption<T> name, T value)
524N/A throws IOException
524N/A {
524N/A if (name == null)
524N/A throw new NullPointerException();
893N/A if (!supportedOptions().contains(name))
893N/A throw new UnsupportedOperationException("'" + name + "' not supported");
524N/A
524N/A synchronized (stateLock) {
524N/A if (!isOpen())
524N/A throw new ClosedChannelException();
524N/A
524N/A // special handling for IP_TOS: no-op when IPv6
4216N/A if (name == StandardSocketOptions.IP_TOS) {
524N/A if (!Net.isIPv6Available())
524N/A Net.setSocketOption(fd, StandardProtocolFamily.INET, name, value);
524N/A return this;
6272N/A } else if (name == StandardSocketOptions.SO_REUSEADDR &&
6272N/A Net.useExclusiveBind())
6272N/A {
6272N/A // SO_REUSEADDR emulated when using exclusive bind
6272N/A isReuseAddress = (Boolean)value;
6272N/A return this;
524N/A }
524N/A
524N/A // no options that require special handling
524N/A Net.setSocketOption(fd, Net.UNSPEC, name, value);
524N/A return this;
524N/A }
524N/A }
524N/A
524N/A @Override
524N/A @SuppressWarnings("unchecked")
524N/A public <T> T getOption(SocketOption<T> name)
524N/A throws IOException
524N/A {
524N/A if (name == null)
524N/A throw new NullPointerException();
893N/A if (!supportedOptions().contains(name))
893N/A throw new UnsupportedOperationException("'" + name + "' not supported");
524N/A
524N/A synchronized (stateLock) {
524N/A if (!isOpen())
524N/A throw new ClosedChannelException();
524N/A
6272N/A if (name == StandardSocketOptions.SO_REUSEADDR &&
6272N/A Net.useExclusiveBind())
6272N/A {
6272N/A // SO_REUSEADDR emulated when using exclusive bind
6272N/A return (T)Boolean.valueOf(isReuseAddress);
6272N/A }
6272N/A
524N/A // special handling for IP_TOS: always return 0 when IPv6
4216N/A if (name == StandardSocketOptions.IP_TOS) {
524N/A return (Net.isIPv6Available()) ? (T) Integer.valueOf(0) :
524N/A (T) Net.getSocketOption(fd, StandardProtocolFamily.INET, name);
524N/A }
524N/A
524N/A // no options that require special handling
524N/A return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
524N/A }
524N/A }
524N/A
893N/A private static class DefaultOptionsHolder {
524N/A static final Set<SocketOption<?>> defaultOptions = defaultOptions();
524N/A
524N/A private static Set<SocketOption<?>> defaultOptions() {
524N/A HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(8);
4216N/A set.add(StandardSocketOptions.SO_SNDBUF);
4216N/A set.add(StandardSocketOptions.SO_RCVBUF);
4216N/A set.add(StandardSocketOptions.SO_KEEPALIVE);
4216N/A set.add(StandardSocketOptions.SO_REUSEADDR);
4216N/A set.add(StandardSocketOptions.SO_LINGER);
4216N/A set.add(StandardSocketOptions.TCP_NODELAY);
524N/A // additional options required by socket adaptor
4216N/A set.add(StandardSocketOptions.IP_TOS);
524N/A set.add(ExtendedSocketOption.SO_OOBINLINE);
524N/A return Collections.unmodifiableSet(set);
524N/A }
524N/A }
524N/A
524N/A @Override
893N/A public final Set<SocketOption<?>> supportedOptions() {
893N/A return DefaultOptionsHolder.defaultOptions;
524N/A }
524N/A
0N/A private boolean ensureReadOpen() throws ClosedChannelException {
0N/A synchronized (stateLock) {
0N/A if (!isOpen())
0N/A throw new ClosedChannelException();
0N/A if (!isConnected())
0N/A throw new NotYetConnectedException();
0N/A if (!isInputOpen)
0N/A return false;
0N/A else
0N/A return true;
0N/A }
0N/A }
0N/A
0N/A private void ensureWriteOpen() throws ClosedChannelException {
0N/A synchronized (stateLock) {
0N/A if (!isOpen())
0N/A throw new ClosedChannelException();
0N/A if (!isOutputOpen)
0N/A throw new ClosedChannelException();
0N/A if (!isConnected())
0N/A throw new NotYetConnectedException();
0N/A }
0N/A }
0N/A
0N/A private void readerCleanup() throws IOException {
0N/A synchronized (stateLock) {
0N/A readerThread = 0;
0N/A if (state == ST_KILLPENDING)
0N/A kill();
0N/A }
0N/A }
0N/A
0N/A private void writerCleanup() throws IOException {
0N/A synchronized (stateLock) {
0N/A writerThread = 0;
0N/A if (state == ST_KILLPENDING)
0N/A kill();
0N/A }
0N/A }
0N/A
0N/A public int read(ByteBuffer buf) throws IOException {
0N/A
0N/A if (buf == null)
0N/A throw new NullPointerException();
0N/A
0N/A synchronized (readLock) {
0N/A if (!ensureReadOpen())
0N/A return -1;
5503N/A Object traceContext = null;
5503N/A if (isBlocking()) {
5766N/A traceContext = IoTrace.socketReadBegin();
5503N/A }
0N/A int n = 0;
0N/A try {
0N/A
0N/A // Set up the interruption machinery; see
0N/A // AbstractInterruptibleChannel for details
0N/A //
0N/A begin();
0N/A
0N/A synchronized (stateLock) {
0N/A if (!isOpen()) {
0N/A // Either the current thread is already interrupted, so
0N/A // begin() closed the channel, or another thread closed the
0N/A // channel since we checked it a few bytecodes ago. In
0N/A // either case the value returned here is irrelevant since
0N/A // the invocation of end() in the finally block will throw
0N/A // an appropriate exception.
0N/A //
0N/A return 0;
0N/A
0N/A }
0N/A
0N/A // Save this thread so that it can be signalled on those
0N/A // platforms that require it
0N/A //
0N/A readerThread = NativeThread.current();
0N/A }
0N/A
0N/A // Between the previous test of isOpen() and the return of the
0N/A // IOUtil.read invocation below, this channel might be closed
0N/A // or this thread might be interrupted. We rely upon the
0N/A // implicit synchronization point in the kernel read() call to
0N/A // make sure that the right thing happens. In either case the
0N/A // implCloseSelectableChannel method is ultimately invoked in
0N/A // some other thread, so there are three possibilities:
0N/A //
0N/A // - implCloseSelectableChannel() invokes nd.preClose()
0N/A // before this thread invokes read(), in which case the
0N/A // read returns immediately with either EOF or an error,
0N/A // the latter of which will cause an IOException to be
0N/A // thrown.
0N/A //
0N/A // - implCloseSelectableChannel() invokes nd.preClose() after
0N/A // this thread is blocked in read(). On some operating
0N/A // systems (e.g., Solaris and Windows) this causes the read
0N/A // to return immediately with either EOF or an error
0N/A // indication.
0N/A //
0N/A // - implCloseSelectableChannel() invokes nd.preClose() after
0N/A // this thread is blocked in read() but the operating
0N/A // system (e.g., Linux) doesn't support preemptive close,
0N/A // so implCloseSelectableChannel() proceeds to signal this
0N/A // thread, thereby causing the read to return immediately
0N/A // with IOStatus.INTERRUPTED.
0N/A //
0N/A // In all three cases the invocation of end() in the finally
0N/A // clause will notice that the channel has been closed and
0N/A // throw an appropriate exception (AsynchronousCloseException
0N/A // or ClosedByInterruptException) if necessary.
0N/A //
0N/A // *There is A fourth possibility. implCloseSelectableChannel()
0N/A // invokes nd.preClose(), signals reader/writer thred and quickly
0N/A // moves on to nd.close() in kill(), which does a real close.
0N/A // Then a third thread accepts a new connection, opens file or
0N/A // whatever that causes the released "fd" to be recycled. All
0N/A // above happens just between our last isOpen() check and the
0N/A // next kernel read reached, with the recycled "fd". The solution
0N/A // is to postpone the real kill() if there is a reader or/and
0N/A // writer thread(s) over there "waiting", leave the cleanup/kill
0N/A // to the reader or writer thread. (the preClose() still happens
0N/A // so the connection gets cut off as usual).
0N/A //
0N/A // For socket channels there is the additional wrinkle that
0N/A // asynchronous shutdown works much like asynchronous close,
0N/A // except that the channel is shutdown rather than completely
0N/A // closed. This is analogous to the first two cases above,
0N/A // except that the shutdown operation plays the role of
0N/A // nd.preClose().
0N/A for (;;) {
6050N/A n = IOUtil.read(fd, buf, -1, nd);
0N/A if ((n == IOStatus.INTERRUPTED) && isOpen()) {
0N/A // The system call was interrupted but the channel
0N/A // is still open, so retry
0N/A continue;
0N/A }
0N/A return IOStatus.normalize(n);
0N/A }
0N/A
0N/A } finally {
0N/A readerCleanup(); // Clear reader thread
5503N/A
5503N/A if (isBlocking()) {
5766N/A IoTrace.socketReadEnd(traceContext, remoteAddress.getAddress(),
5766N/A remoteAddress.getPort(), 0, n > 0 ? n : 0);
5503N/A }
5503N/A
0N/A // The end method, which is defined in our superclass
0N/A // AbstractInterruptibleChannel, resets the interruption
0N/A // machinery. If its argument is true then it returns
0N/A // normally; otherwise it checks the interrupt and open state
0N/A // of this channel and throws an appropriate exception if
0N/A // necessary.
0N/A //
0N/A // So, if we actually managed to do any I/O in the above try
0N/A // block then we pass true to the end method. We also pass
0N/A // true if the channel was in non-blocking mode when the I/O
0N/A // operation was initiated but no data could be transferred;
0N/A // this prevents spurious exceptions from being thrown in the
0N/A // rare event that a channel is closed or a thread is
0N/A // interrupted at the exact moment that a non-blocking I/O
0N/A // request is made.
0N/A //
0N/A end(n > 0 || (n == IOStatus.UNAVAILABLE));
0N/A
0N/A // Extra case for socket channels: Asynchronous shutdown
0N/A //
0N/A synchronized (stateLock) {
0N/A if ((n <= 0) && (!isInputOpen))
0N/A return IOStatus.EOF;
0N/A }
0N/A
0N/A assert IOStatus.check(n);
0N/A
0N/A }
0N/A }
0N/A }
0N/A
2655N/A public long read(ByteBuffer[] dsts, int offset, int length)
2655N/A throws IOException
2655N/A {
2655N/A if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
2655N/A throw new IndexOutOfBoundsException();
0N/A synchronized (readLock) {
0N/A if (!ensureReadOpen())
0N/A return -1;
0N/A long n = 0;
5503N/A Object traceContext = null;
5503N/A if (isBlocking()) {
5766N/A traceContext = IoTrace.socketReadBegin();
5503N/A }
0N/A try {
0N/A begin();
0N/A synchronized (stateLock) {
0N/A if (!isOpen())
0N/A return 0;
0N/A readerThread = NativeThread.current();
0N/A }
0N/A
0N/A for (;;) {
2655N/A n = IOUtil.read(fd, dsts, offset, length, nd);
0N/A if ((n == IOStatus.INTERRUPTED) && isOpen())
0N/A continue;
0N/A return IOStatus.normalize(n);
0N/A }
0N/A } finally {
0N/A readerCleanup();
5503N/A if (isBlocking()) {
5766N/A IoTrace.socketReadEnd(traceContext, remoteAddress.getAddress(),
5766N/A remoteAddress.getPort(), 0, n > 0 ? n : 0);
5503N/A }
0N/A end(n > 0 || (n == IOStatus.UNAVAILABLE));
0N/A synchronized (stateLock) {
0N/A if ((n <= 0) && (!isInputOpen))
0N/A return IOStatus.EOF;
0N/A }
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public int write(ByteBuffer buf) throws IOException {
0N/A if (buf == null)
0N/A throw new NullPointerException();
0N/A synchronized (writeLock) {
0N/A ensureWriteOpen();
0N/A int n = 0;
5503N/A Object traceContext =
5766N/A IoTrace.socketWriteBegin();
5503N/A
0N/A try {
0N/A begin();
0N/A synchronized (stateLock) {
0N/A if (!isOpen())
0N/A return 0;
0N/A writerThread = NativeThread.current();
0N/A }
0N/A for (;;) {
6050N/A n = IOUtil.write(fd, buf, -1, nd);
0N/A if ((n == IOStatus.INTERRUPTED) && isOpen())
0N/A continue;
0N/A return IOStatus.normalize(n);
0N/A }
0N/A } finally {
0N/A writerCleanup();
5766N/A IoTrace.socketWriteEnd(traceContext, remoteAddress.getAddress(),
5766N/A remoteAddress.getPort(), n > 0 ? n : 0);
0N/A end(n > 0 || (n == IOStatus.UNAVAILABLE));
0N/A synchronized (stateLock) {
0N/A if ((n <= 0) && (!isOutputOpen))
0N/A throw new AsynchronousCloseException();
0N/A }
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A }
0N/A
2655N/A public long write(ByteBuffer[] srcs, int offset, int length)
2655N/A throws IOException
2655N/A {
2655N/A if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
2655N/A throw new IndexOutOfBoundsException();
0N/A synchronized (writeLock) {
0N/A ensureWriteOpen();
0N/A long n = 0;
5503N/A Object traceContext =
5766N/A IoTrace.socketWriteBegin();
0N/A try {
0N/A begin();
0N/A synchronized (stateLock) {
0N/A if (!isOpen())
0N/A return 0;
0N/A writerThread = NativeThread.current();
0N/A }
0N/A for (;;) {
2655N/A n = IOUtil.write(fd, srcs, offset, length, nd);
0N/A if ((n == IOStatus.INTERRUPTED) && isOpen())
0N/A continue;
0N/A return IOStatus.normalize(n);
0N/A }
0N/A } finally {
0N/A writerCleanup();
5766N/A IoTrace.socketWriteEnd(traceContext, remoteAddress.getAddress(),
5766N/A remoteAddress.getPort(), n > 0 ? n : 0);
0N/A end((n > 0) || (n == IOStatus.UNAVAILABLE));
0N/A synchronized (stateLock) {
0N/A if ((n <= 0) && (!isOutputOpen))
0N/A throw new AsynchronousCloseException();
0N/A }
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A }
0N/A
2614N/A // package-private
2614N/A int sendOutOfBandData(byte b) throws IOException {
2614N/A synchronized (writeLock) {
2614N/A ensureWriteOpen();
2614N/A int n = 0;
2614N/A try {
2614N/A begin();
2614N/A synchronized (stateLock) {
2614N/A if (!isOpen())
2614N/A return 0;
2614N/A writerThread = NativeThread.current();
2614N/A }
2614N/A for (;;) {
2614N/A n = sendOutOfBandData(fd, b);
2614N/A if ((n == IOStatus.INTERRUPTED) && isOpen())
2614N/A continue;
2614N/A return IOStatus.normalize(n);
2614N/A }
2614N/A } finally {
2614N/A writerCleanup();
2614N/A end((n > 0) || (n == IOStatus.UNAVAILABLE));
2614N/A synchronized (stateLock) {
2614N/A if ((n <= 0) && (!isOutputOpen))
2614N/A throw new AsynchronousCloseException();
2614N/A }
2614N/A assert IOStatus.check(n);
2614N/A }
2614N/A }
2614N/A }
2614N/A
0N/A protected void implConfigureBlocking(boolean block) throws IOException {
0N/A IOUtil.configureBlocking(fd, block);
0N/A }
0N/A
6319N/A public InetSocketAddress localAddress() {
0N/A synchronized (stateLock) {
0N/A return localAddress;
0N/A }
0N/A }
0N/A
0N/A public SocketAddress remoteAddress() {
0N/A synchronized (stateLock) {
0N/A return remoteAddress;
0N/A }
0N/A }
0N/A
524N/A @Override
524N/A public SocketChannel bind(SocketAddress local) throws IOException {
0N/A synchronized (readLock) {
0N/A synchronized (writeLock) {
0N/A synchronized (stateLock) {
524N/A if (!isOpen())
524N/A throw new ClosedChannelException();
524N/A if (state == ST_PENDING)
524N/A throw new ConnectionPendingException();
0N/A if (localAddress != null)
0N/A throw new AlreadyBoundException();
524N/A InetSocketAddress isa = (local == null) ?
524N/A new InetSocketAddress(0) : Net.checkAddress(local);
1040N/A NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
0N/A Net.bind(fd, isa.getAddress(), isa.getPort());
0N/A localAddress = Net.localAddress(fd);
0N/A }
0N/A }
0N/A }
524N/A return this;
0N/A }
0N/A
0N/A public boolean isConnected() {
0N/A synchronized (stateLock) {
0N/A return (state == ST_CONNECTED);
0N/A }
0N/A }
0N/A
0N/A public boolean isConnectionPending() {
0N/A synchronized (stateLock) {
0N/A return (state == ST_PENDING);
0N/A }
0N/A }
0N/A
0N/A void ensureOpenAndUnconnected() throws IOException { // package-private
0N/A synchronized (stateLock) {
0N/A if (!isOpen())
0N/A throw new ClosedChannelException();
0N/A if (state == ST_CONNECTED)
0N/A throw new AlreadyConnectedException();
0N/A if (state == ST_PENDING)
0N/A throw new ConnectionPendingException();
0N/A }
0N/A }
0N/A
0N/A public boolean connect(SocketAddress sa) throws IOException {
0N/A int localPort = 0;
0N/A
0N/A synchronized (readLock) {
0N/A synchronized (writeLock) {
0N/A ensureOpenAndUnconnected();
0N/A InetSocketAddress isa = Net.checkAddress(sa);
0N/A SecurityManager sm = System.getSecurityManager();
0N/A if (sm != null)
0N/A sm.checkConnect(isa.getAddress().getHostAddress(),
0N/A isa.getPort());
0N/A synchronized (blockingLock()) {
0N/A int n = 0;
0N/A try {
0N/A try {
0N/A begin();
0N/A synchronized (stateLock) {
0N/A if (!isOpen()) {
0N/A return false;
0N/A }
1040N/A // notify hook only if unbound
1040N/A if (localAddress == null) {
1040N/A NetHooks.beforeTcpConnect(fd,
1040N/A isa.getAddress(),
1040N/A isa.getPort());
1040N/A }
0N/A readerThread = NativeThread.current();
0N/A }
0N/A for (;;) {
0N/A InetAddress ia = isa.getAddress();
0N/A if (ia.isAnyLocalAddress())
0N/A ia = InetAddress.getLocalHost();
0N/A n = Net.connect(fd,
0N/A ia,
524N/A isa.getPort());
0N/A if ( (n == IOStatus.INTERRUPTED)
0N/A && isOpen())
0N/A continue;
0N/A break;
0N/A }
524N/A
0N/A } finally {
0N/A readerCleanup();
0N/A end((n > 0) || (n == IOStatus.UNAVAILABLE));
0N/A assert IOStatus.check(n);
0N/A }
0N/A } catch (IOException x) {
0N/A // If an exception was thrown, close the channel after
0N/A // invoking end() so as to avoid bogus
0N/A // AsynchronousCloseExceptions
0N/A close();
0N/A throw x;
0N/A }
0N/A synchronized (stateLock) {
0N/A remoteAddress = isa;
0N/A if (n > 0) {
0N/A
0N/A // Connection succeeded; disallow further
0N/A // invocation
0N/A state = ST_CONNECTED;
5016N/A if (isOpen())
5016N/A localAddress = Net.localAddress(fd);
0N/A return true;
0N/A }
0N/A // If nonblocking and no exception then connection
0N/A // pending; disallow another invocation
0N/A if (!isBlocking())
0N/A state = ST_PENDING;
0N/A else
0N/A assert false;
0N/A }
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A }
0N/A
0N/A public boolean finishConnect() throws IOException {
0N/A synchronized (readLock) {
0N/A synchronized (writeLock) {
0N/A synchronized (stateLock) {
0N/A if (!isOpen())
0N/A throw new ClosedChannelException();
0N/A if (state == ST_CONNECTED)
0N/A return true;
0N/A if (state != ST_PENDING)
0N/A throw new NoConnectionPendingException();
0N/A }
0N/A int n = 0;
0N/A try {
0N/A try {
0N/A begin();
0N/A synchronized (blockingLock()) {
0N/A synchronized (stateLock) {
0N/A if (!isOpen()) {
0N/A return false;
0N/A }
0N/A readerThread = NativeThread.current();
0N/A }
0N/A if (!isBlocking()) {
0N/A for (;;) {
0N/A n = checkConnect(fd, false,
0N/A readyToConnect);
0N/A if ( (n == IOStatus.INTERRUPTED)
0N/A && isOpen())
0N/A continue;
0N/A break;
0N/A }
0N/A } else {
0N/A for (;;) {
0N/A n = checkConnect(fd, true,
0N/A readyToConnect);
0N/A if (n == 0) {
0N/A // Loop in case of
0N/A // spurious notifications
0N/A continue;
0N/A }
0N/A if ( (n == IOStatus.INTERRUPTED)
0N/A && isOpen())
0N/A continue;
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A } finally {
0N/A synchronized (stateLock) {
0N/A readerThread = 0;
0N/A if (state == ST_KILLPENDING) {
0N/A kill();
0N/A // poll()/getsockopt() does not report
0N/A // error (throws exception, with n = 0)
0N/A // on Linux platform after dup2 and
0N/A // signal-wakeup. Force n to 0 so the
0N/A // end() can throw appropriate exception
0N/A n = 0;
0N/A }
0N/A }
0N/A end((n > 0) || (n == IOStatus.UNAVAILABLE));
0N/A assert IOStatus.check(n);
0N/A }
0N/A } catch (IOException x) {
0N/A // If an exception was thrown, close the channel after
0N/A // invoking end() so as to avoid bogus
0N/A // AsynchronousCloseExceptions
0N/A close();
0N/A throw x;
0N/A }
0N/A if (n > 0) {
0N/A synchronized (stateLock) {
0N/A state = ST_CONNECTED;
5016N/A if (isOpen())
5016N/A localAddress = Net.localAddress(fd);
0N/A }
0N/A return true;
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A }
0N/A
524N/A @Override
524N/A public SocketChannel shutdownInput() throws IOException {
0N/A synchronized (stateLock) {
0N/A if (!isOpen())
0N/A throw new ClosedChannelException();
524N/A if (!isConnected())
524N/A throw new NotYetConnectedException();
524N/A if (isInputOpen) {
524N/A Net.shutdown(fd, Net.SHUT_RD);
524N/A if (readerThread != 0)
524N/A NativeThread.signal(readerThread);
524N/A isInputOpen = false;
524N/A }
524N/A return this;
0N/A }
0N/A }
0N/A
524N/A @Override
524N/A public SocketChannel shutdownOutput() throws IOException {
0N/A synchronized (stateLock) {
0N/A if (!isOpen())
0N/A throw new ClosedChannelException();
524N/A if (!isConnected())
524N/A throw new NotYetConnectedException();
524N/A if (isOutputOpen) {
524N/A Net.shutdown(fd, Net.SHUT_WR);
524N/A if (writerThread != 0)
524N/A NativeThread.signal(writerThread);
524N/A isOutputOpen = false;
524N/A }
524N/A return this;
0N/A }
0N/A }
0N/A
0N/A public boolean isInputOpen() {
0N/A synchronized (stateLock) {
0N/A return isInputOpen;
0N/A }
0N/A }
0N/A
0N/A public boolean isOutputOpen() {
0N/A synchronized (stateLock) {
0N/A return isOutputOpen;
0N/A }
0N/A }
0N/A
0N/A // AbstractInterruptibleChannel synchronizes invocations of this method
0N/A // using AbstractInterruptibleChannel.closeLock, and also ensures that this
0N/A // method is only ever invoked once. Before we get to this method, isOpen
0N/A // (which is volatile) will have been set to false.
0N/A //
0N/A protected void implCloseSelectableChannel() throws IOException {
0N/A synchronized (stateLock) {
0N/A isInputOpen = false;
0N/A isOutputOpen = false;
0N/A
0N/A // Close the underlying file descriptor and dup it to a known fd
0N/A // that's already closed. This prevents other operations on this
0N/A // channel from using the old fd, which might be recycled in the
0N/A // meantime and allocated to an entirely different channel.
0N/A //
4963N/A if (state != ST_KILLED)
4963N/A nd.preClose(fd);
0N/A
0N/A // Signal native threads, if needed. If a target thread is not
0N/A // currently blocked in an I/O operation then no harm is done since
0N/A // the signal handler doesn't actually do anything.
0N/A //
0N/A if (readerThread != 0)
0N/A NativeThread.signal(readerThread);
0N/A
0N/A if (writerThread != 0)
0N/A NativeThread.signal(writerThread);
0N/A
0N/A // If this channel is not registered then it's safe to close the fd
0N/A // immediately since we know at this point that no thread is
0N/A // blocked in an I/O operation upon the channel and, since the
0N/A // channel is marked closed, no thread will start another such
0N/A // operation. If this channel is registered then we don't close
0N/A // the fd since it might be in use by a selector. In that case
0N/A // closing this channel caused its keys to be cancelled, so the
0N/A // last selector to deregister a key for this channel will invoke
0N/A // kill() to close the fd.
0N/A //
0N/A if (!isRegistered())
0N/A kill();
0N/A }
0N/A }
0N/A
0N/A public void kill() throws IOException {
0N/A synchronized (stateLock) {
0N/A if (state == ST_KILLED)
0N/A return;
0N/A if (state == ST_UNINITIALIZED) {
0N/A state = ST_KILLED;
0N/A return;
0N/A }
0N/A assert !isOpen() && !isRegistered();
0N/A
0N/A // Postpone the kill if there is a waiting reader
0N/A // or writer thread. See the comments in read() for
0N/A // more detailed explanation.
0N/A if (readerThread == 0 && writerThread == 0) {
0N/A nd.close(fd);
0N/A state = ST_KILLED;
0N/A } else {
0N/A state = ST_KILLPENDING;
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Translates native poll revent ops into a ready operation ops
0N/A */
0N/A public boolean translateReadyOps(int ops, int initialOps,
0N/A SelectionKeyImpl sk) {
0N/A int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
0N/A int oldOps = sk.nioReadyOps();
0N/A int newOps = initialOps;
0N/A
0N/A if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
0N/A // This should only happen if this channel is pre-closed while a
0N/A // selection operation is in progress
0N/A // ## Throw an error if this channel has not been pre-closed
0N/A return false;
0N/A }
0N/A
0N/A if ((ops & (PollArrayWrapper.POLLERR
0N/A | PollArrayWrapper.POLLHUP)) != 0) {
0N/A newOps = intOps;
0N/A sk.nioReadyOps(newOps);
0N/A // No need to poll again in checkConnect,
0N/A // the error will be detected there
0N/A readyToConnect = true;
0N/A return (newOps & ~oldOps) != 0;
0N/A }
0N/A
0N/A if (((ops & PollArrayWrapper.POLLIN) != 0) &&
0N/A ((intOps & SelectionKey.OP_READ) != 0) &&
0N/A (state == ST_CONNECTED))
0N/A newOps |= SelectionKey.OP_READ;
0N/A
0N/A if (((ops & PollArrayWrapper.POLLCONN) != 0) &&
0N/A ((intOps & SelectionKey.OP_CONNECT) != 0) &&
0N/A ((state == ST_UNCONNECTED) || (state == ST_PENDING))) {
0N/A newOps |= SelectionKey.OP_CONNECT;
0N/A readyToConnect = true;
0N/A }
0N/A
0N/A if (((ops & PollArrayWrapper.POLLOUT) != 0) &&
0N/A ((intOps & SelectionKey.OP_WRITE) != 0) &&
0N/A (state == ST_CONNECTED))
0N/A newOps |= SelectionKey.OP_WRITE;
0N/A
0N/A sk.nioReadyOps(newOps);
0N/A return (newOps & ~oldOps) != 0;
0N/A }
0N/A
0N/A public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
0N/A return translateReadyOps(ops, sk.nioReadyOps(), sk);
0N/A }
0N/A
0N/A public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
0N/A return translateReadyOps(ops, 0, sk);
0N/A }
0N/A
0N/A /**
0N/A * Translates an interest operation set into a native poll event set
0N/A */
0N/A public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
0N/A int newOps = 0;
0N/A if ((ops & SelectionKey.OP_READ) != 0)
0N/A newOps |= PollArrayWrapper.POLLIN;
0N/A if ((ops & SelectionKey.OP_WRITE) != 0)
0N/A newOps |= PollArrayWrapper.POLLOUT;
0N/A if ((ops & SelectionKey.OP_CONNECT) != 0)
0N/A newOps |= PollArrayWrapper.POLLCONN;
0N/A sk.selector.putEventOps(sk, newOps);
0N/A }
0N/A
0N/A public FileDescriptor getFD() {
0N/A return fd;
0N/A }
0N/A
0N/A public int getFDVal() {
0N/A return fdVal;
0N/A }
0N/A
6319N/A @Override
0N/A public String toString() {
0N/A StringBuffer sb = new StringBuffer();
0N/A sb.append(this.getClass().getSuperclass().getName());
0N/A sb.append('[');
0N/A if (!isOpen())
0N/A sb.append("closed");
0N/A else {
0N/A synchronized (stateLock) {
0N/A switch (state) {
0N/A case ST_UNCONNECTED:
0N/A sb.append("unconnected");
0N/A break;
0N/A case ST_PENDING:
0N/A sb.append("connection-pending");
0N/A break;
0N/A case ST_CONNECTED:
0N/A sb.append("connected");
0N/A if (!isInputOpen)
0N/A sb.append(" ishut");
0N/A if (!isOutputOpen)
0N/A sb.append(" oshut");
0N/A break;
0N/A }
6319N/A InetSocketAddress addr = localAddress();
6319N/A if (addr != null) {
0N/A sb.append(" local=");
6319N/A sb.append(Net.getRevealedLocalAddressAsString(addr));
0N/A }
0N/A if (remoteAddress() != null) {
0N/A sb.append(" remote=");
0N/A sb.append(remoteAddress().toString());
0N/A }
0N/A }
0N/A }
0N/A sb.append(']');
0N/A return sb.toString();
0N/A }
0N/A
0N/A
0N/A // -- Native methods --
0N/A
0N/A private static native int checkConnect(FileDescriptor fd,
0N/A boolean block, boolean ready)
0N/A throws IOException;
0N/A
2614N/A private static native int sendOutOfBandData(FileDescriptor fd, byte data)
2614N/A throws IOException;
2614N/A
0N/A static {
0N/A Util.load();
0N/A nd = new SocketDispatcher();
0N/A }
0N/A
0N/A}