/* * Copyright 2007-2010 Sun Microsystems, Inc. * * This file is part of Project Darkstar Server. * * Project Darkstar Server is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation and * distributed hereunder to you. * * Project Darkstar Server is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Sun designates this particular file as subject to the "Classpath" * exception as provided by Sun in the LICENSE file that accompanied * this code. * * -- */ package com.sun.sgs.nio.channels; import java.io.IOException; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AlreadyConnectedException; import java.nio.channels.ClosedChannelException; import java.nio.channels.ConnectionPendingException; import java.nio.channels.NotYetConnectedException; import java.nio.channels.UnresolvedAddressException; import java.nio.channels.UnsupportedAddressTypeException; import java.util.concurrent.TimeUnit; import com.sun.sgs.nio.channels.spi.AsynchronousChannelProvider; /** * An asynchronous channel for stream-oriented connecting sockets. * <p> * Asynchronous socket channels are created in one of two ways. A * newly-created AsynchronousSocketChannel is created by invoking one of the * open methods defined by this class. A newly-created channel is open but * not yet connected. A connected AsynchronousSocketChannel is created when * a connection is made to the socket of an AsynchronousServerSocketChannel. * It is not possible to create an asynchronous socket channel for an * arbitrary, pre-existing socket. * <p> * A newly-created channel is connected by invoking its connect method; once * connected, a channel remains connected until it is closed. Whether or not * a socket channel is connected may be determined by invoking its * getConnectedAddress method. Whether or not a connect operation is in * progress may be determined by invoking the isConnectionPending method. An * attempt to invoke an I/O operation upon an unconnected channel will cause * a NotYetConnectedException to be thrown. * <p> * Channels of this type are safe for use by multiple concurrent threads. * They support concurrent reading and writing, though at most one read * operation and one write operation can be outstanding at any time. If a * thread initiates a read operation before a previous read operation has * completed then a ReadPendingException will be thrown. Similarly, an * attempt to initiate a write operation before a previous write has * completed will throw a WritePendingException. Whether or not a read or * write operation is pending may be determined by invoking the * isReadPending and isWritePending methods. * <p> * Socket options are configured using the setOption method. Asynchronous * socket channels support the following options: * <blockquote> * <table> * <tr> * <th>Option Name</th> * <th>Description</th> * </tr> * <tr> * <td>{@link StandardSocketOption#SO_SNDBUF SO_SNDBUF}</td> * <td>The size of the socket send buffer</td> * </tr> * <tr> * <td>{@link StandardSocketOption#SO_RCVBUF SO_RCVBUF}</td> * <td> The size of the socket receive buffer </td> * </tr> * <tr> * <td>{@link StandardSocketOption#SO_KEEPALIVE SO_KEEPALIVE}</td> * <td>Keep connection alive</td> * </tr> * <tr> * <td>{@link StandardSocketOption#SO_REUSEADDR SO_REUSEADDR}</td> * <td>Re-use address</td> * </tr> * <tr> * <td>{@link StandardSocketOption#TCP_NODELAY TCP_NODELAY}</td> * <td>Disable the Nagle algorithm</td> * </tr> * </table> * </blockquote> * and may support additional (implementation * specific) options. The list of options supported is obtained by invoking * the options method. * <h4>Timeouts</h4> * The read and write methods defined by this class allow a timeout to be * specified when initiating a read or write operation. If the timeout * elapses before an operation completes then the operation completes by * throwing ExecutionException with cause AbortedByTimeoutException. A * timeout may leave the channel, or the underlying connection, in an * inconsistent state. Where an implementation cannot guarantee that no * bytes have been read from the channel then it puts the channel into an * implementation specific error state and a subsequent attempt to initiate * a read operation throws an unspecified runtime exception. Similarly if a * write operation times and the implementation cannot guarantee that no * bytes have been written to the channel then it prohibits further write * operations by throwing an unspecified runtime exception. * <p> * When a timeout elapses then the state of the ByteBuffer, or the sequence * of buffers, for the I/O operation is not defined. Buffers should be * discarded or at least care must be taken to ensure that the buffers are * not accessed while the channel remains open. */ public abstract class AsynchronousSocketChannel extends AsynchronousChannel implements AsynchronousByteChannel, NetworkChannel { /** * Initializes a new instance of this class. * * @param provider the asynchronous channel provider for this channel */ protected AsynchronousSocketChannel(AsynchronousChannelProvider provider) { super(provider); } /** * Opens an asynchronous socket channel. * <p> * The new channel is created by invoking the * openAsynchronousSocketChannel method on the * AsynchronousChannelProvider object that created the given group. * If the group parameter is null then the resulting channel is created * by the system-wide default provider, and bound to the default group. * * @param group the group to which the newly constructed channel should * be bound, or null for the default group * @return a new asynchronous socket channel * @throws ShutdownChannelGroupException if the specified group is shutdown * @throws IOException if an I/O error occurs */ public static AsynchronousSocketChannel open(AsynchronousChannelGroup group) throws IOException { return AsynchronousChannelProvider.provider(). openAsynchronousSocketChannel(group); } /** * Opens an asynchronous socket channel. * <p> * This method returns an asynchronous socket channel that is bound * to the default group.This method is equivalent to evaluating the * expression: * <pre> * open((AsynchronousChannelGroup)null); * </pre> * @return a new asynchronous socket channel * @throws IOException if an I/O error occurs */ public static AsynchronousSocketChannel open() throws IOException { return open((AsynchronousChannelGroup) null); } /** * {@inheritDoc} */ public abstract AsynchronousSocketChannel bind(SocketAddress local) throws IOException; /** * {@inheritDoc} */ public abstract AsynchronousSocketChannel setOption(SocketOption name, Object value) throws IOException; /** * Shutdown a connection for reading and/or writing without closing the * channel. * <p> * The how parameter specifies if the input, output, or both sides of * the connection is shutdown. If the input side of the connection is * shutdown then further read operations on the channel will return -1, * the end-of-stream indication. If the input side of the connection is * already shutdown then invoking this method to shutdown the input side * of the connection has no effect. If the output side of the connection * is shutdown then further write operations on the channel will * complete immediately by throwning ExecutionException with cause * ClosedChannelException. If the output side of the connection is * already shutdown then invoking this method to shutdown the output * side of the connection has no effect. * * @param how specifies if the input, output, or both sides of the * connection is shutdown * @return this channel * @throws NotYetConnectedException if this channel is not yet connected * @throws ClosedChannelException if this channel is closed * @throws IOException if some other I/O error occurs */ public abstract AsynchronousSocketChannel shutdown(ShutdownType how) throws IOException; /** * Returns the remote address to which this channel's socket is * connected, or null if the channel's socket is not connected. * * @return the remote address; null if the channel is not open or the * channel's socket is not connected * @throws IOException if an I/O error occurs */ public abstract SocketAddress getConnectedAddress() throws IOException; /** * Tells whether or not a connect is pending for this channel. * <p> * The result of this method is a snapshot of the channel state. It may * be invalid when the caller goes to examine the result and should not * be used for purposes of coordination. * * @return true if, and only if, a connect is pending for this * channel but has not yet completed */ public abstract boolean isConnectionPending(); /** * Tells whether or not a read is pending for this channel. * <p> * The result of this method is a snapshot of the channel state. It may * be invalid when the caller goes to examine the result and should not * be used for purposes of coordination. * * @return true if, and only if, a read is pending for this this channel * but has not yet completed * @see ReadPendingException */ public abstract boolean isReadPending(); /** * Tells whether or not a write is pending for this channel. * <p> * The result of this method is a snapshot of the channel state. It may * be invalid when the caller goes to examine the result and should not * be used for purposes of coordination. * * @return true if, and only if, a write is pending for this this * channel but has not yet completed * @see WritePendingException */ public abstract boolean isWritePending(); /** * Connects this channel. * <p> * This method initiates an operation to connect this channel, returning * a IoFuture representing the pending result of the operation. If the * connection is successfully established then the IoFuture's get method * will return null, otherwise it throws ExecutionException with the * approach cause. * <p> * This method performs exactly the same security checks as the Socket * class. That is, if a security manager has been installed then this * method verifies that its checkConnect method permits connecting to * the address and port number of the given remote endpoint. * * @param <A> the attachment type * @param remote the remote address to which this channel is to be * connected * @param attachment the object to attach to the returned IoFuture * object; can be null * @param handler the handler for consuming the result; can be null * @return an IoFuture object representing the pending result * @throws ClosedAsynchronousChannelException if this channel is closed * @throws AlreadyConnectedException if this channel is already * connected * @throws ConnectionPendingException if a connection operation is * already in progress on this channel * @throws UnresolvedAddressException if the given remote address is not * fully resolved * @throws UnsupportedAddressTypeException if the type of the given * remote address is not supported * @throws SecurityException if a security manager has been installed * and it does not permit access to the given remote endpoint * @see #getConnectedAddress() * @see #isConnectionPending() */ public abstract <A> IoFuture<Void, A> connect(SocketAddress remote, A attachment, CompletionHandler<Void, ? super A> handler); /** * Connects this channel. * <p> * This method initiates an operation to connect this channel, returning * a IoFuture representing the pending result of the operation. If the * connection is successfully established then the IoFuture's get method * will return null. * <p> * This method is equivalent to invoking * connect(SocketAddress,A,CompletionHandler) with the attachment * parameter set to null. * * @param <A> the attachment type * @param remote the remote address to which this channel is to be * connected * @param handler the handler for consuming the result; can be null * @return an IoFuture object representing the pending result * @throws ClosedAsynchronousChannelException if this channel is closed * @throws AlreadyConnectedException if this channel is already * connected * @throws ConnectionPendingException if a connection operation is * already in progress on this channel * @throws UnresolvedAddressException if the given remote address is not * fully resolved * @throws UnsupportedAddressTypeException if the type of the given * remote address is not supported * @throws SecurityException if a security manager has been installed * and it does not permit access to the given remote endpoint * @see #getConnectedAddress() * @see #isConnectionPending() */ public final <A> IoFuture<Void, A> connect(SocketAddress remote, CompletionHandler<Void, ? super A> handler) { return connect(remote, null, handler); } /** * Reads a sequence of bytes from this channel into the given buffer. * <p> * This method initiates the reading of a sequence of bytes from this * channel into the given buffer, returning an IoFuture representing the * pending result of the operation. The IoFuture's get method returns * the number of bytes read, possibly zero, or -1 if all bytes have been * read and channel has reached end-of-stream. * <p> * If a timeout is specified and the timeout elapses before the * operation completes then it completes with ExecutionException and * cause AbortedByTimeoutException. In that case it is guranteed that no * bytes have been read from the channel into the given buffer. * <p> * Otherwise this method works in the same manner as the * AsynchronousByteChannel.read(ByteBuffer,A,CompletionHandler) method. * * @param <A> the attachment type * @param dst the buffer into which bytes are to be transferred * @param timeout the timeout, or 0L for no timeout * @param unit the time unit of the timeout argument * @param attachment the object to attach to the returned IoFuture * object; can be null * @param handler the handler for consuming the result; can be null * @return an IoFuture object representing the pending result * @throws IllegalArgumentException if the timeout parameter is negative * @throws ClosedAsynchronousChannelException if this channel is closed * @throws ReadPendingException if a read operation is already in * progress on this channel * @throws NotYetConnectedException if this channel is not yet connected * @throws IllegalChannelStateException if a previous read operation on * the channel completed due to a timeout */ public abstract <A> IoFuture<Integer, A> read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler); /** * Reads a sequence of bytes from this channel into the given buffer. * <p> * This method initiates the reading of a sequence of bytes from this * channel into the given buffer, returning an IoFuture representing the * pending result of the operation. The IoFuture's get method will * return the number of bytes read, possibly zero, or -1 if all bytes * have been read and channel has reached end-of-stream. * <p> * This method is equivalent to invoking * read(ByteBuffer,long,TimeUnit,A,CompletionHandler) with a timeout of * 0L. * * @param <A> the attachment type * @param dst the buffer into which bytes are to be transferred * @param attachment the object to attach to the returned IoFuture * object; can be null * @param handler the handler for consuming the result; can be null * @return an IoFuture object representing the pending result * @throws ClosedAsynchronousChannelException if this channel is closed * @throws ReadPendingException if a read operation is already in * progress on this channel * @throws NotYetConnectedException if this channel is not yet connected * @throws IllegalChannelStateException if a previous read operation on * the channel completed due to a timeout */ public final <A> IoFuture<Integer, A> read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) { return read(dst, 0L, TimeUnit.NANOSECONDS, attachment, handler); } /** * Reads a sequence of bytes from this channel into the given buffer. * <p> * This method initiates the reading of a sequence of bytes from this * channel into the given buffer, returning an IoFuture representing the * pending result of the operation. The IoFuture's get method will * return the number of bytes read, possibly zero, or -1 if all bytes * have been read and channel has reached end-of-stream. * <p> * This method is equivalent to invoking * read(ByteBuffer,long,TimeUnit,A,CompletionHandler) with a timeout of * 0L, and an attachment of null. * * @param <A> the attachment type * @param dst the buffer into which bytes are to be transferred * @param handler the handler for consuming the result; can be null * @return an IoFuture object representing the pending result * @throws ClosedAsynchronousChannelException if this channel is closed * @throws ReadPendingException if a read operation is already in * progress on this channel * @throws NotYetConnectedException if this channel is not yet connected * @throws IllegalChannelStateException if a previous read operation on * the channel completed due to a timeout */ public final <A> IoFuture<Integer, A> read(ByteBuffer dst, CompletionHandler<Integer, ? super A> handler) { return read(dst, 0L, TimeUnit.NANOSECONDS, null, handler); } /** * Reads a sequence of bytes from this channel into a subsequence of the * given buffers. * <p> * This method initiates the reading of a sequence of bytes from this * channel into a subsequence of the given buffers, returning an * IoFuture representing the pending result of the operation. The * IoFuture's get method returns the number of bytes read, possibly * zero, or -1 if all bytes have been read and channel has reached * end-of-stream. * <p> * This method initiates a read of up to r bytes from this channel, * where r is the total number of bytes remaining in the specified * subsequence of the given buffer array, that is, * <pre> * dsts[offset].remaining() * + dsts[offset+1].remaining() * + ... + dsts[offset+length-1].remaining() * </pre> * at the moment that the read is attempted. * <p> * Suppose that a byte sequence of length n is read, where 0 <= n <= r. * Up to the first dsts[offset].remaining() bytes of this sequence are * transferred into buffer dsts[offset], up to the next * dsts[offset+1].remaining() bytes are transferred into buffer * dsts[offset+1], and so forth, until the entire byte sequence is * transferred into the given buffers. As many bytes as possible are * transferred into each buffer, hence the final position of each * updated buffer, except the last updated buffer, is guaranteed to be * equal to that buffer's limit. * <p> * If a timeout is specified and the timeout elapses before the * operation completes then it completes with ExecutionException and * cause AbortedByTimeoutException. In that case it is guranteed that no * bytes have been read from the channel into the given buffers. * * @param <A> the attachment type * @param dsts the buffers into which bytes are to be transferred * @param offset the offset within the buffer array of the first buffer * into which bytes are to be transferred; must be non-negative * and no larger than dsts.length * @param length the maximum number of buffers to be accessed; must be * non-negative and no larger than dsts.length - offset * @param timeout the timeout, or 0L for no timeout * @param unit the time unit of the timeout argument * @param attachment the object to attach to the returned IoFuture * object; can be null * @param handler the handler for consuming the result; can be null * @return an IoFuture object representing the pending result * @throws IllegalArgumentException if the timeout parameter is * negative, or the pre-conditions for the offset and length * parameter aren't met * @throws ClosedAsynchronousChannelException if this channel is closed * @throws ReadPendingException if a read operation is already in * progress on this channel * @throws NotYetConnectedException if this channel is not yet connected * @throws IllegalChannelStateException if a previous read operation on * the channel completed due to a timeout */ public abstract <A> IoFuture<Long, A> read(ByteBuffer[] dsts, int offset, int length, long timeout, TimeUnit unit, A attachment, CompletionHandler<Long, ? super A> handler); /** * Writes a sequence of bytes to this channel from the given buffer. * <p> * This method initiates the writing of a sequence of bytes to this * channel from the given buffer, returning an IoFuture representing the * pending result of the operation. The IoFuture's get method will * return the number of bytes written, possibly zero. * <p> * If a timeout is specified and the timeout elapses before the * operation completes then it completes with ExecutionException and * cause AbortedByTimeoutException. In that case it is guranteed that no * bytes have written to the channel from the given buffer. * <p> * Otherwise this method works in the same manner as the * AsynchronousByteChannel.write(ByteBuffer,A,CompletionHandler) method. * * @param <A> the attachment type * @param src the buffer from which bytes are to be retrieved * @param timeout the timeout, or 0L for no timeout * @param unit the time unit of the timeout argument * @param attachment the object to attach to the returned IoFuture * object; can be null * @param handler the handler for consuming the result; can be null * @return an IoFuture object representing the pending result * @throws IllegalArgumentException if the timeout parameter is negative * @throws ClosedAsynchronousChannelException if this channel is closed * @throws WritePendingException if a write operation is already in * progress on this channel * @throws NotYetConnectedException if this channel is not yet connected * @throws IllegalChannelStateException if a previous write operation on * the channel completed due to a timeout */ public abstract <A> IoFuture<Integer, A> write(ByteBuffer src, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler); /** * Writes a sequence of bytes to this channel from the given buffer. * <p> * This method initiates the writing of a sequence of bytes to this * channel rom the given buffer, returning an IoFuture representing the * pending result of the operation. * <p> * This method is equivalent to invoking * write(ByteBuffer,long,TimeUnit,A,CompletionHandler) with a timeout of * 0L. * * @param <A> the attachment type * @param src the buffer from which bytes are to be retrieved * @param attachment the object to attach to the returned IoFuture * object; can be null * @param handler the handler for consuming the result; can be null * @return an IoFuture object representing the pending result * @throws ClosedAsynchronousChannelException if this channel is closed * @throws WritePendingException if a write operation is already in * progress on this channel * @throws NotYetConnectedException if this channel is not yet connected * @throws IllegalChannelStateException if a previous write operation on * the channel completed due to a timeout */ public final <A> IoFuture<Integer, A> write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) { return write(src, 0L, TimeUnit.NANOSECONDS, attachment, handler); } /** * Writes a sequence of bytes to this channel from the given buffer. * <p> * This method initiates the writing of a sequence of bytes to this * channel from the given buffer, returning an IoFuture representing the * pending result of the operation. * <p> * This method is equivalent to invoking * write(ByteBuffer,long,TimeUnit,A,CompletionHandler) with a timeout of * 0L, and an attachment of null. * * @param <A> the attachment type * @param src the buffer from which bytes are to be retrieved * @param handler the handler for consuming the result; can be null * @return an IoFuture object representing the pending result * @throws ClosedAsynchronousChannelException if this channel is closed * @throws WritePendingException if a write operation is already in * progress on this channel * @throws NotYetConnectedException if this channel is not yet connected * @throws IllegalChannelStateException if a previous write operation on * the channel completed due to a timeout */ public final <A> IoFuture<Integer, A> write(ByteBuffer src, CompletionHandler<Integer, ? super A> handler) { return write(src, 0L, TimeUnit.NANOSECONDS, null, handler); } /** * Writes a sequence of bytes to this channel from a subsequence of the * given buffers. * <p> * This method initiates the writing of a sequence of bytes to this * channel from a subsequence of the given buffers, returning an * IoFuture representing the pending result of the operation. The * IoFuture's get method will return the number of bytes written, * possibly zero. * <p> * This method initiates a write of up to r bytes to this channel, where * r is the total number of bytes remaining in the specified subsequence * of the given buffer array, that is, * <pre> * srcs[offset].remaining() * + srcs[offset+1].remaining() * + ... + srcs[offset+length-1].remaining() * </pre> * at the moment that the write is attempted. * <p> * Suppose that a byte sequence of length n is written, where 0 <= n <= * r. Up to the first srcs[offset].remaining() bytes of this sequence * are written from buffer srcs[offset], up to the next * srcs[offset+1].remaining() bytes are written from buffer * srcs[offset+1], and so forth, until the entire byte sequence is * written. As many bytes as possible are written from each buffer, * hence the final position of each updated buffer, except the last * updated buffer, is guaranteed to be equal to that buffer's limit. * <p> * If a timeout is specified and the timeout elapses before the * operation completes then it completes with ExecutionException and * cause AbortedByTimeoutException. In that case it is guranteed that no * bytes have written to the channel from the given buffers. * * @param <A> the attachment type * @param srcs the buffers from which bytes are to be retrieved * @param offset the offset within the buffer array of the first buffer * from which bytes are to be retrieved; must be non-negative and * no larger than srcs.length. * @param length the maximum number of buffers to be accessed; must be * non-negative and no larger than srcs.length - offset * @param timeout the timeout, or 0L for no timeout * @param unit the time unit of the timeout argument * @param attachment the object to attach to the returned IoFuture * object; can be null * @param handler the handler for consuming the result; can be null * @return an IoFuture object representing the pending result * @throws IllegalArgumentException if the timeout parameter is negative * or the pre-conditions for the offset or length parameter * aren't met * @throws ClosedAsynchronousChannelException if this channel is closed * @throws WritePendingException if a write operation is already in * progress on this channel * @throws NotYetConnectedException if this channel is not yet connected * @throws IllegalChannelStateException if a previous write operation on * the channel completed due to a timeout */ public abstract <A> IoFuture<Long, A> write(ByteBuffer[] srcs, int offset, int length, long timeout, TimeUnit unit, A attachment, CompletionHandler<Long, ? super A> handler); }