public class SslConnection extends AbstractConnection implements Connection.UpgradeTo
Connection
like HttpConnection) that
wants unencrypted data.
The connector uses an EndPoint
(typically SocketChannelEndPoint) as
it's source/sink of encrypted data. It then provides an endpoint via getDecryptedEndPoint()
to
expose a source/sink of unencrypted data to another connection (eg HttpConnection).
The design of this class is based on a clear separation between the passive methods, which do not block nor schedule any asynchronous callbacks, and active methods that do schedule asynchronous callbacks.
The passive methods are SslConnection.DecryptedEndPoint.fill(ByteBuffer)
and SslConnection.DecryptedEndPoint.flush(ByteBuffer...)
. They make best
effort attempts to progress the connection using only calls to the encrypted EndPoint.fill(ByteBuffer)
and EndPoint.flush(ByteBuffer...)
methods. They will never block nor schedule any readInterest or write callbacks. If a fill/flush cannot progress either because
of network congestion or waiting for an SSL handshake message, then the fill/flush will simply return with zero bytes filled/flushed.
Specifically, if a flush cannot proceed because it needs to receive a handshake message, then the flush will attempt to fill bytes from the
encrypted endpoint, but if insufficient bytes are read it will NOT call EndPoint.fillInterested(Callback)
.
It is only the active methods : AbstractEndPoint.fillInterested(Callback)
and
AbstractEndPoint.write(Callback, ByteBuffer...)
that may schedule callbacks by calling the encrypted
EndPoint.fillInterested(Callback)
and EndPoint.write(Callback, ByteBuffer...)
methods. For normal data handling, the decrypted fillInterest method will result in an encrypted fillInterest and a decrypted
write will result in an encrypted write. However, due to SSL handshaking requirements, it is also possible for a decrypted fill
to call the encrypted write and for the decrypted flush to call the encrypted fillInterested methods.
MOST IMPORTANTLY, the encrypted callbacks from the active methods (#onFillable() and WriteFlusher#completeWrite()) do no filling or flushing themselves. Instead they simple make the callbacks to the decrypted callbacks, so that the passive encrypted fill/flush will be called again and make another best effort attempt to progress the connection.
Modifier and Type | Class and Description |
---|---|
class |
SslConnection.DecryptedEndPoint |
private static class |
SslConnection.FillState |
private static class |
SslConnection.FlushState |
private static class |
SslConnection.HandshakeState |
private class |
SslConnection.RunnableTask |
Connection.Listener, Connection.UpgradeFrom, Connection.UpgradeTo
Modifier and Type | Field and Description |
---|---|
private ByteBufferPool |
_bufferPool |
private boolean |
_closedOutbound |
private boolean |
_decryptedDirectBuffers |
private SslConnection.DecryptedEndPoint |
_decryptedEndPoint |
private java.nio.ByteBuffer |
_decryptedInput |
private boolean |
_encryptedDirectBuffers |
private java.nio.ByteBuffer |
_encryptedInput |
private java.nio.ByteBuffer |
_encryptedOutput |
private SslConnection.FillState |
_fillState |
private SslConnection.FlushState |
_flushState |
private java.util.concurrent.atomic.AtomicReference<SslConnection.HandshakeState> |
_handshake |
private boolean |
_renegotiationAllowed |
private int |
_renegotiationLimit |
private boolean |
_requireCloseMessage |
private java.lang.Runnable |
_runFillable |
private javax.net.ssl.SSLEngine |
_sslEngine |
private Callback |
_sslReadCallback |
private boolean |
_underflown |
private java.util.List<SslHandshakeListener> |
handshakeListeners |
private static Logger |
LOG |
private static java.lang.String |
TLS_1_3 |
Constructor and Description |
---|
SslConnection(ByteBufferPool byteBufferPool,
java.util.concurrent.Executor executor,
EndPoint endPoint,
javax.net.ssl.SSLEngine sslEngine) |
SslConnection(ByteBufferPool byteBufferPool,
java.util.concurrent.Executor executor,
EndPoint endPoint,
javax.net.ssl.SSLEngine sslEngine,
boolean useDirectBuffersForEncryption,
boolean useDirectBuffersForDecryption) |
Modifier and Type | Method and Description |
---|---|
private void |
acquireEncryptedInput() |
private void |
acquireEncryptedOutput() |
void |
addHandshakeListener(SslHandshakeListener listener) |
void |
close()
Performs a logical close of this connection.
|
private int |
getApplicationBufferSize() |
private int |
getBufferSize(java.util.function.ToIntFunction<javax.net.ssl.SSLSession> bufferSizeFn) |
SslConnection.DecryptedEndPoint |
getDecryptedEndPoint() |
private int |
getPacketBufferSize() |
int |
getRenegotiationLimit() |
javax.net.ssl.SSLEngine |
getSSLEngine() |
boolean |
isAllowMissingCloseMessage()
Deprecated.
use inverted
isRequireCloseMessage() instead |
private boolean |
isHandshakeComplete() |
private boolean |
isHandshakeInitial() |
private boolean |
isHandshakeSucceeded() |
boolean |
isRenegotiationAllowed() |
boolean |
isRequireCloseMessage() |
protected int |
networkFill(java.nio.ByteBuffer input) |
protected boolean |
networkFlush(java.nio.ByteBuffer output) |
protected SslConnection.DecryptedEndPoint |
newDecryptedEndPoint() |
void |
onClose()
Callback method invoked when this connection is closed.
|
void |
onFillable()
Callback method invoked when the endpoint is ready to be read.
|
void |
onFillInterestedFailed(java.lang.Throwable cause)
Callback method invoked when the endpoint failed to be ready to be read.
|
boolean |
onIdleExpired()
Callback method invoked upon an idle timeout event.
|
void |
onOpen()
Callback method invoked when this connection is opened.
|
void |
onUpgradeTo(java.nio.ByteBuffer buffer)
Callback method invoked when this connection is upgraded.
|
protected void |
releaseDecryptedInputBuffer() |
private void |
releaseEncryptedInputBuffer() |
private void |
releaseEncryptedOutputBuffer() |
boolean |
removeHandshakeListener(SslHandshakeListener listener) |
void |
setAllowMissingCloseMessage(boolean allowMissingCloseMessage)
Deprecated.
use inverted
setRequireCloseMessage(boolean) instead |
void |
setRenegotiationAllowed(boolean renegotiationAllowed) |
void |
setRenegotiationLimit(int renegotiationLimit) |
void |
setRequireCloseMessage(boolean requireCloseMessage)
Sets whether it is required that a peer send the TLS
close_notify message
to indicate the will to close the connection, otherwise it may be interpreted as a
truncation attack. |
java.lang.String |
toConnectionString() |
protected javax.net.ssl.SSLEngineResult |
unwrap(javax.net.ssl.SSLEngine sslEngine,
java.nio.ByteBuffer input,
java.nio.ByteBuffer output) |
protected javax.net.ssl.SSLEngineResult |
wrap(javax.net.ssl.SSLEngine sslEngine,
java.nio.ByteBuffer[] input,
java.nio.ByteBuffer output) |
addListener, failedCallback, fillInterested, getBytesIn, getBytesOut, getCreatedTimeStamp, getEndPoint, getExecutor, getInputBufferSize, getMessagesIn, getMessagesOut, isFillInterested, onReadTimeout, removeListener, setInputBufferSize, toString, tryFillInterested, tryFillInterested
private static final Logger LOG
private static final java.lang.String TLS_1_3
private final java.util.List<SslHandshakeListener> handshakeListeners
private final ByteBufferPool _bufferPool
private final javax.net.ssl.SSLEngine _sslEngine
private final SslConnection.DecryptedEndPoint _decryptedEndPoint
private java.nio.ByteBuffer _decryptedInput
private java.nio.ByteBuffer _encryptedInput
private java.nio.ByteBuffer _encryptedOutput
private final boolean _encryptedDirectBuffers
private final boolean _decryptedDirectBuffers
private boolean _renegotiationAllowed
private int _renegotiationLimit
private boolean _closedOutbound
private boolean _requireCloseMessage
private SslConnection.FlushState _flushState
private SslConnection.FillState _fillState
private java.util.concurrent.atomic.AtomicReference<SslConnection.HandshakeState> _handshake
private boolean _underflown
private final java.lang.Runnable _runFillable
private final Callback _sslReadCallback
public SslConnection(ByteBufferPool byteBufferPool, java.util.concurrent.Executor executor, EndPoint endPoint, javax.net.ssl.SSLEngine sslEngine)
public SslConnection(ByteBufferPool byteBufferPool, java.util.concurrent.Executor executor, EndPoint endPoint, javax.net.ssl.SSLEngine sslEngine, boolean useDirectBuffersForEncryption, boolean useDirectBuffersForDecryption)
public void addHandshakeListener(SslHandshakeListener listener)
public boolean removeHandshakeListener(SslHandshakeListener listener)
protected SslConnection.DecryptedEndPoint newDecryptedEndPoint()
public javax.net.ssl.SSLEngine getSSLEngine()
public SslConnection.DecryptedEndPoint getDecryptedEndPoint()
public boolean isRenegotiationAllowed()
public void setRenegotiationAllowed(boolean renegotiationAllowed)
public int getRenegotiationLimit()
public void setRenegotiationLimit(int renegotiationLimit)
renegotiationLimit
- The number of renegotiations allowed for this connection.
When the limit is 0 renegotiation will be denied. If the limit is less than 0 then no limit is applied.
Default -1.@Deprecated public boolean isAllowMissingCloseMessage()
isRequireCloseMessage()
insteadclose_notify
message@Deprecated public void setAllowMissingCloseMessage(boolean allowMissingCloseMessage)
setRequireCloseMessage(boolean)
insteadallowMissingCloseMessage
- whether is not required that peers send the TLS close_notify
messagepublic boolean isRequireCloseMessage()
close_notify
messagepublic void setRequireCloseMessage(boolean requireCloseMessage)
Sets whether it is required that a peer send the TLS close_notify
message
to indicate the will to close the connection, otherwise it may be interpreted as a
truncation attack.
This option is only useful on clients, since typically servers cannot accept connection-delimited content that may be truncated.
requireCloseMessage
- whether peers must send the TLS close_notify
messageprivate boolean isHandshakeInitial()
private boolean isHandshakeSucceeded()
private boolean isHandshakeComplete()
private int getApplicationBufferSize()
private int getPacketBufferSize()
private int getBufferSize(java.util.function.ToIntFunction<javax.net.ssl.SSLSession> bufferSizeFn)
private void acquireEncryptedInput()
private void acquireEncryptedOutput()
public void onUpgradeTo(java.nio.ByteBuffer buffer)
Connection.UpgradeTo
Callback method invoked when this connection is upgraded.
This must be called before Connection.onOpen()
.
onUpgradeTo
in interface Connection.UpgradeTo
buffer
- An optional buffer that can contain prefilled data. Typically this
results from an upgrade of one protocol to the other where the old connection has buffered
data destined for the new connection. The new connection must take ownership of the buffer
and is responsible for returning it to the buffer poolpublic void onOpen()
Connection
Callback method invoked when this connection is opened.
Creators of the connection implementation are responsible for calling this method.
onOpen
in interface Connection
onOpen
in class AbstractConnection
public void onClose()
Connection
Callback method invoked when this connection is closed.
Creators of the connection implementation are responsible for calling this method.
onClose
in interface Connection
onClose
in class AbstractConnection
public void close()
Connection
Performs a logical close of this connection.
For simple connections, this may just mean to delegate the close to the associated
EndPoint
but, for example, SSL connections should write the SSL close message
before closing the associated EndPoint
.
close
in interface java.io.Closeable
close
in interface java.lang.AutoCloseable
close
in interface Connection
close
in class AbstractConnection
public boolean onIdleExpired()
Connection
Callback method invoked upon an idle timeout event.
Implementations of this method may return true to indicate that the idle timeout handling should proceed normally, typically failing the EndPoint and causing it to be closed.
When false is returned, the handling of the idle timeout event is halted immediately and the EndPoint left in the state it was before the idle timeout event.
onIdleExpired
in interface Connection
onIdleExpired
in class AbstractConnection
public void onFillable()
AbstractConnection
Callback method invoked when the endpoint is ready to be read.
onFillable
in class AbstractConnection
AbstractConnection.fillInterested()
public void onFillInterestedFailed(java.lang.Throwable cause)
AbstractConnection
Callback method invoked when the endpoint failed to be ready to be read.
onFillInterestedFailed
in class AbstractConnection
cause
- the exception that caused the failureprotected javax.net.ssl.SSLEngineResult wrap(javax.net.ssl.SSLEngine sslEngine, java.nio.ByteBuffer[] input, java.nio.ByteBuffer output) throws javax.net.ssl.SSLException
javax.net.ssl.SSLException
protected javax.net.ssl.SSLEngineResult unwrap(javax.net.ssl.SSLEngine sslEngine, java.nio.ByteBuffer input, java.nio.ByteBuffer output) throws javax.net.ssl.SSLException
javax.net.ssl.SSLException
public java.lang.String toConnectionString()
toConnectionString
in class AbstractConnection
private void releaseEncryptedInputBuffer()
protected void releaseDecryptedInputBuffer()
private void releaseEncryptedOutputBuffer()
protected int networkFill(java.nio.ByteBuffer input) throws java.io.IOException
java.io.IOException
protected boolean networkFlush(java.nio.ByteBuffer output) throws java.io.IOException
java.io.IOException