All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.io.EndPoint Maven / Gradle / Ivy

There is a newer version: 12.1.0.alpha0
Show newest version
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.io;

import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ReadPendingException;
import java.nio.channels.WritePendingException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLSession;

import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.Invocable;

/**
 * 

EndPoint is the abstraction for I/O communication using bytes.

*

All the I/O methods are non-blocking; reads may return {@code 0} * bytes read, and flushes/writes may write {@code 0} bytes.

*

Applications are notified of read readiness by registering a * {@link Callback} via {@link #fillInterested(Callback)}, and then * using {@link #fill(ByteBuffer)} to read the available bytes.

*

Application may use {@link #flush(ByteBuffer...)} to transmit bytes; * if the flush does not transmit all the bytes, applications must * arrange to resume flushing when it will be possible to transmit more * bytes. * Alternatively, applications may use {@link #write(Callback, ByteBuffer...)} * and be notified via the {@link Callback} when the write completes * (i.e. all the buffers have been flushed), either successfully or * with a failure.

*

Connection-less reads are performed using {@link #receive(ByteBuffer)}. * Similarly, connection-less flushes are performed using * {@link #send(SocketAddress, ByteBuffer...)} and connection-less writes * using {@link #write(Callback, SocketAddress, ByteBuffer...)}.

*

While all the I/O methods are non-blocking, they can be easily * converted to blocking using either {@link org.eclipse.jetty.util.Blocker} * or {@link Callback.Completable}:

*
{@code
 * EndPoint endPoint = ...;
 *
 * // Block until read ready with Blocker.
 * try (Blocker.Callback blocker = Blocker.callback())
 * {
 *     endPoint.fillInterested(blocker);
 *     blocker.block();
 * }
 *
 * // Block until write complete with Callback.Completable.
 * Callback.Completable completable = new Callback.Completable();
 * endPoint.write(completable, byteBuffer);
 * completable.get();
 * }
*/ public interface EndPoint extends Closeable { /** *

Constant returned by {@link #receive(ByteBuffer)} to indicate the end-of-file.

*/ SocketAddress EOF = InetSocketAddress.createUnresolved("", 0); /** * Marks an {@code EndPoint} that wraps another {@code EndPoint}. */ interface Wrapper { /** * @return The wrapped {@code EndPoint} */ EndPoint unwrap(); } /** * @return The local InetSocketAddress to which this {@code EndPoint} is bound, or {@code null} * if this {@code EndPoint} is not bound to a Socket address. * @deprecated use {@link #getLocalSocketAddress()} instead */ @Deprecated InetSocketAddress getLocalAddress(); /** * @return the local SocketAddress to which this {@code EndPoint} is bound or {@code null} * if this {@code EndPoint} is not bound to a Socket address. */ default SocketAddress getLocalSocketAddress() { return getLocalAddress(); } /** * @return The remote InetSocketAddress to which this {@code EndPoint} is connected, or {@code null} * if this {@code EndPoint} is not connected to a Socket address. * @deprecated use {@link #getRemoteSocketAddress()} instead. */ @Deprecated InetSocketAddress getRemoteAddress(); /** * @return The remote SocketAddress to which this {@code EndPoint} is connected, or {@code null} * if this {@code EndPoint} is not connected to a Socket address. */ default SocketAddress getRemoteSocketAddress() { return getRemoteAddress(); } /** * @return whether this EndPoint is open */ boolean isOpen(); /** * @return the epoch time in milliseconds when this EndPoint was created */ long getCreatedTimeStamp(); /** *

Shuts down the output.

*

This call indicates that no more data will be sent from this endpoint and * that the remote endpoint should read an EOF once all previously sent data has been * read. Shutdown may be done either at the TCP/IP level, as a protocol exchange * (for example, TLS close handshake) or both.

*

If the endpoint has {@link #isInputShutdown()} true, then this call has the * same effect as {@link #close()}.

*/ void shutdownOutput(); /** *

Tests if output is shutdown.

*

The output is shutdown by a call to {@link #shutdownOutput()} * or {@link #close()}.

* * @return true if the output is shutdown or the endpoint is closed. */ boolean isOutputShutdown(); /** *

Tests if the input is shutdown.

*

The input is shutdown if an EOF has been read while doing * a {@link #fill(ByteBuffer)}. * Once the input is shutdown, all calls to * {@link #fill(ByteBuffer)} will return -1, until such time as the * end point is close, when they will return {@link EofException}.

* * @return true if the input is shutdown or the endpoint is closed. */ boolean isInputShutdown(); /** *

Closes any backing stream associated with the endpoint.

*/ @Override default void close() { close(null); } /** *

Closes any backing stream associated with the endpoint, passing a * possibly {@code null} failure cause.

* * @param cause the reason for the close or null */ void close(Throwable cause); /** *

Fills the passed buffer with data from this endpoint.

*

The bytes are appended to any data already in the buffer * by writing from the buffers limit up to its capacity. * The limit is updated to include the filled bytes.

* * @param buffer The buffer to fill. The position and limit are modified during the fill. After the * operation, the position is unchanged and the limit is increased to reflect the new data filled. * @return an {@code int} value indicating the number of bytes * filled or -1 if EOF is read or the input is shutdown. * @throws IOException if the endpoint is closed. */ default int fill(ByteBuffer buffer) throws IOException { throw new UnsupportedOperationException(); } /** *

Receives data into the given buffer from the returned address.

*

This method should be used to receive UDP data.

* * @param buffer the buffer to fill with data * @return the peer address that sent the data, or {@link #EOF} * @throws IOException if the receive fails */ default SocketAddress receive(ByteBuffer buffer) throws IOException { int filled = fill(buffer); if (filled < 0) return EndPoint.EOF; if (filled == 0) return null; return getRemoteSocketAddress(); } /** *

Flushes data from the passed header/buffer to this endpoint.

*

As many bytes as can be consumed are taken from the header/buffer * position up until the buffer limit. * The header/buffers position is updated to indicate how many bytes * have been consumed.

* * @param buffer the buffers to flush * @return True IFF all the buffers have been consumed and the endpoint has flushed the data to its * destination (ie is not buffering any data). * @throws IOException If the endpoint is closed or output is shutdown. */ default boolean flush(ByteBuffer... buffer) throws IOException { throw new UnsupportedOperationException(); } /** *

Sends to the given address the data in the given buffers.

*

This methods should be used to send UDP data.

* * @param address the peer address to send data to * @param buffers the buffers containing the data to send * @return true if all the buffers have been consumed * @throws IOException if the send fails * @see #write(Callback, SocketAddress, ByteBuffer...) */ default boolean send(SocketAddress address, ByteBuffer... buffers) throws IOException { return flush(buffers); } /** * @return The underlying transport object (socket, channel, etc.) */ Object getTransport(); /** *

Returns the idle timeout in ms.

*

The idle timeout is the time the endpoint can be idle before * its close is initiated.

*

A timeout less than or equal to {@code 0} implies an infinite timeout.

* * @return the idle timeout in ms */ long getIdleTimeout(); /** *

Sets the idle timeout.

* * @param idleTimeout the idle timeout in MS. Timeout <= 0 implies an infinite timeout */ void setIdleTimeout(long idleTimeout); /** *

Requests callback methods to be invoked when a call to {@link #fill(ByteBuffer)} would return data or EOF.

* * @param callback the callback to call when an error occurs or we are readable. The callback may implement the {@link Invocable} interface to * self declare its blocking status. Non-blocking callbacks may be called more efficiently without dispatch delays. * @throws ReadPendingException if another read operation is concurrent. */ void fillInterested(Callback callback) throws ReadPendingException; /** *

Requests callback methods to be invoked when a call to {@link #fill(ByteBuffer)} would return data or EOF.

* * @param callback the callback to call when an error occurs or we are readable. The callback may implement the {@link Invocable} interface to * self declare its blocking status. Non-blocking callbacks may be called more efficiently without dispatch delays. * @return true if set */ boolean tryFillInterested(Callback callback); /** * @return whether {@link #fillInterested(Callback)} has been called, but {@link #fill(ByteBuffer)} has not yet * been called */ boolean isFillInterested(); /** *

Writes the given buffers via {@link #flush(ByteBuffer...)} and invokes callback methods when either * all the data has been flushed or an error occurs.

* * @param callback the callback to call when an error occurs or the write completed. The callback may implement the {@link Invocable} interface to * self declare its blocking status. Non-blocking callbacks may be called more efficiently without dispatch delays. * @param buffers one or more {@link ByteBuffer}s that will be flushed. * @throws WritePendingException if another write operation is concurrent. */ default void write(Callback callback, ByteBuffer... buffers) throws WritePendingException { throw new UnsupportedOperationException(); } /** *

Writes to the given address the data contained in the given buffers, and invokes * the given callback when either all the data has been sent, or a failure occurs.

* * @param callback the callback to notify of the success or failure of the write operation * @param address the peer address to send data to * @param buffers the buffers containing the data to send * @throws WritePendingException if a previous write was initiated but was not yet completed * @see #send(SocketAddress, ByteBuffer...) */ default void write(Callback callback, SocketAddress address, ByteBuffer... buffers) throws WritePendingException { write(callback, buffers); } /** * @return the {@link Connection} associated with this EndPoint * @see #setConnection(Connection) */ Connection getConnection(); /** * @param connection the {@link Connection} associated with this EndPoint * @see #getConnection() * @see #upgrade(Connection) */ void setConnection(Connection connection); /** *

Callback method invoked when this EndPoint is opened.

* * @see #onClose(Throwable) */ void onOpen(); /** *

Callback method invoked when this {@link EndPoint} is closed.

* * @param cause The reason for the close, or null if a normal close. * @see #onOpen() */ void onClose(Throwable cause); /** *

Upgrades this EndPoint from the current connection to the given new connection.

*

Closes the current connection, links this EndPoint to the new connection and * then opens the new connection.

*

If the current connection is an instance of {@link Connection.UpgradeFrom} then * a buffer of unconsumed bytes is requested. * If the buffer of unconsumed bytes is non-null and non-empty, then the new * connection is tested: if it is an instance of {@link Connection.UpgradeTo}, then * the unconsumed buffer is passed to the new connection; otherwise, an exception * is thrown since there are unconsumed bytes that cannot be consumed by the new * connection.

* * @param newConnection the connection to upgrade to */ void upgrade(Connection newConnection); /** *

Returns the SslSessionData of a secure end point.

* * @return A {@link SslSessionData} instance (with possibly null field values) if secure, else {@code null}. */ default SslSessionData getSslSessionData() { return null; } /** * @return whether this EndPoint represents a secure communication. */ default boolean isSecure() { return getSslSessionData() != null; } /** * Interface representing bundle of SSLSession associated data. */ interface SslSessionData { /** * The name at which an {@code SslSessionData} instance may be found * as a request {@link org.eclipse.jetty.util.Attributes attribute}. */ String ATTRIBUTE = "org.eclipse.jetty.io.Endpoint.SslSessionData"; /** * @return The {@link SSLSession} itself, if known, else {@code null}. */ SSLSession sslSession(); /** * @return The {@link SSLSession#getId()} rendered as a hex string, if known, else {@code null}. */ String sslSessionId(); /** * @return The {@link SSLSession#getCipherSuite()} if known, else {@code null}. */ String cipherSuite(); /** * @return The {@link SSLSession#getPeerCertificates()}s converted to {@link X509Certificate}, if known, else {@code null}. */ X509Certificate[] peerCertificates(); /** * Calculates the key size based on the cipher suite. * @return the key size. */ default int keySize() { String cipherSuite = cipherSuite(); return cipherSuite == null ? 0 : SslContextFactory.deduceKeyLength(cipherSuite); } static SslSessionData from(SSLSession sslSession, String sslSessionId, String cipherSuite, X509Certificate[] peerCertificates) { return new SslSessionData() { @Override public SSLSession sslSession() { return sslSession; } @Override public String sslSessionId() { return sslSessionId; } @Override public String cipherSuite() { return cipherSuite; } @Override public X509Certificate[] peerCertificates() { return peerCertificates; } }; } static SslSessionData withCipherSuite(SslSessionData baseData, String cipherSuite) { return (baseData == null) ? from(null, null, cipherSuite, null) : from( baseData.sslSession(), baseData.sslSessionId(), cipherSuite != null ? cipherSuite : baseData.cipherSuite(), baseData.peerCertificates()); } static SslSessionData withSslSessionId(SslSessionData baseData, String sslSessionId) { return (baseData == null) ? from(null, sslSessionId, null, null) : from( baseData.sslSession(), sslSessionId != null ? sslSessionId : baseData.sslSessionId(), baseData.cipherSuite(), baseData.peerCertificates()); } } /** *

A communication conduit between two peers.

*/ interface Pipe { /** * @return the {@link EndPoint} of the local peer */ EndPoint getLocalEndPoint(); /** * @return the {@link EndPoint} of the remote peer */ EndPoint getRemoteEndPoint(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy