public final class SecureSocket extends java.lang.Object implements SocketIF
SocketIF
. This class implements all
logic required to process SSL/TLS handshaking and encrypt/decrypt data being
sent and received through the underlying SocketChannel
. Note that this class is declared as final as it should NOT be extended.
Constructor and Description |
---|
SecureSocket(java.nio.channels.SocketChannel channel,
javax.net.ssl.SSLEngine engine,
boolean singleThreaded,
TaskWorker taskWorker,
TimeoutWorker toWorker,
HandshakeListener hsListener,
TimeoutListener toListener)
Create a new instance of a
SecureSocket . |
Modifier and Type | Method and Description |
---|---|
void |
close()
Pass-through implementation of
AbstractInterruptibleChannel.close() . |
java.nio.channels.SelectableChannel |
configureBlocking(boolean block)
Pass-through implementation of
AbstractSelectableChannel.configureBlocking(boolean block) |
boolean |
connect(java.net.SocketAddress remote)
Pass-through implementation of
SocketChannel.connect(SocketAddress remote) |
boolean |
finishConnect()
Pass-through implementation of
SocketChannel.finishConnect() In
the SecureSocket implementation, once the connection of the
underlying SocketChannel is finished, the SSL/TLS handshake is
manually initiated here. |
javax.net.ssl.SSLEngine |
getEngine()
Get the associated underlying
SSLEngine . |
java.nio.channels.SocketChannel |
getSocket()
Returns the underlying
SocketChannel . |
boolean |
handshakePending()
Used to identify whether the handshaking performed from the underlying
SSLEngine is still pending. |
void |
initHandshake()
Initialize SSL/TLS handshaking.
|
void |
invalidateSession()
Invalidate the current
SSLSession . |
void |
processHandshake()
Performs SSL/TLS handshaking.
|
int |
read(java.nio.ByteBuffer buffer)
Reads a sequence of bytes from this channel into the given buffer.
|
java.nio.channels.SelectionKey |
register(java.nio.channels.Selector sel,
int ops)
Pass-through implementation of
SelectableChannel.register(Selector sel, int ops) |
void |
setTaskPending(boolean taskPending)
Sets whether or not there is an
SSLEngine task pending, during an
SSL/TLS handshake. |
void |
updateResult()
Update the
SSLEngineResult and setTaskPending(boolean)
to false. |
int |
write(java.nio.ByteBuffer buffer)
Pass-through implementation of
SocketChannel.write(ByteBuffer buffer) |
public SecureSocket(java.nio.channels.SocketChannel channel, javax.net.ssl.SSLEngine engine, boolean singleThreaded, TaskWorker taskWorker, TimeoutWorker toWorker, HandshakeListener hsListener, TimeoutListener toListener)
SecureSocket
. This instance has all
the necessary logic to perform an SSL/TLS handshake and to encrypt and
decrypt data being sent and received through the underlying
SocketChannel
.channel
- The underlying SocketChannelengine
- The underlying SSLEnginesingleThreaded
- Whether or not this socket should perform the
SSLEngineResult#HandshakeStatus
NEED_TASK in the same thread
(true) or in the TaskWorker
thread (false). If set to true, null
can be passed for the TaskWorker
instance.taskWorker
- The TaskWorker
instance associated with this
SecureSocket. Can be null if this socket performs the
SSLEngineResult#HandshakeStatus
NEED_TASK in the same threadtoWorker
- The TimeoutWorker
instance associated with this
SecureSocket.hsListener
- The HandshakeListener
associated with this
SecureSocket. Only one handshake listener is associated per socket, which
is usually the AbstractSelector
implementation.toListener
- The TimeoutListener
associated with this
SecureSocket. Only one timeout listener is associated per socket, which
is usually the AbstractSelector
implementation.public javax.net.ssl.SSLEngine getEngine()
SSLEngine
. This method is called
from the TaskWorker
when there are pending SSLEngine tasks to be
run.SSLEngine
associated with this socket.public void invalidateSession()
SSLSession
. This method could be
periodically used via a Timeout
to perform SSL/TLS session
rotation if needed.invalidateSession
in interface SocketIF
public void initHandshake() throws java.io.IOException
AbstractSelector
thread in two cases: (1) when
finishConnect()
is called or (2) when the SSLSession
has
been previously invalidated.initHandshake
in interface SocketIF
java.io.IOException
- propagated exceptions from
processHandshake()
javax.net.ssl.SSLException
- if there is an SSL/TLS problem with the call to the
underlying SSLEngine.beginHandshake()
.initHandshake()
public java.nio.channels.SocketChannel getSocket()
SocketChannel
. This is done in order to
register the current socket with a Selector
, as only the
SocketChannel
implementation is allowed to be associated with a
Selector
.public boolean connect(java.net.SocketAddress remote) throws java.io.IOException
SocketChannel.connect(SocketAddress remote)
connect
in interface SocketIF
remote
- The remote address to which this channel is to be connectedjava.io.IOException
- Propagated exceptions from the underlying
SocketChannel.connect(SocketAddress remote)
implementation.public boolean finishConnect() throws java.io.IOException
SocketChannel.finishConnect()
In
the SecureSocket
implementation, once the connection of the
underlying SocketChannel
is finished, the SSL/TLS handshake is
manually initiated here. Note that this is not strictly necessary but
rather a convenience, as subsequent handshakes can be initiated from the
read(ByteBuffer buffer)
and
write(ByteBuffer buffer)
methods.
finishConnect
in interface SocketIF
java.io.IOException
- Propagated exceptions from the underlying
SocketChannel.finishConnect()
implementation.public java.nio.channels.SelectionKey register(java.nio.channels.Selector sel, int ops) throws java.nio.channels.ClosedChannelException
SelectableChannel.register(Selector sel, int ops)
register
in interface SocketIF
sel
- The selector with which this channel is to be registeredops
- The interest set for the resulting keyjava.nio.channels.ClosedChannelException
- Propagated exceptions from the underlying
SelectableChannel.register(Selector sel, int ops)
implementation.public java.nio.channels.SelectableChannel configureBlocking(boolean block) throws java.io.IOException
AbstractSelectableChannel.configureBlocking(boolean block)
configureBlocking
in interface SocketIF
block
- If true then this channel will be placed in blocking mode;
if false then it will be placed in non-blocking modejava.io.IOException
- Propagated exceptions from the underlying
AbstractSelectableChannel.configureBlocking(boolean block)
implementation.public void processHandshake() throws java.io.IOException
TaskWorker
thread, based on how the
SecureSocket
has been initialized.processHandshake
in interface SocketIF
java.io.IOException
- If there is an underlying IOException while
performing the handshakejavax.net.ssl.SSLException
- If there is an exception thrown by the underlying
SSLEngine
while performing the handshakeprocessHandshake()
public void updateResult()
SSLEngineResult
and setTaskPending(boolean)
to false. This method is called once the SSLEngine
has no
more pending tasks. The updated result is fused from both the previous
SSLEngineResult
and the SSLEngine.getHandshakeStatus()
.
This is done such that we can receive the FINISHED
SSLEngineResult.handshakeStatus
that would otherwise not be
available by just updating the existing SSLEngineResult
.
We
also setTaskPending(boolean)
to false as there are no more tasks
needed to be completed for the underlying SSLEngine
.
updateResult
in interface SocketIF
updateResult()
public int read(java.nio.ByteBuffer buffer) throws java.io.IOException
read(ByteBuffer buffer)
, with additional logic to
handle the SSL/TLS encrypted stream. An attempt is made to read up to
r bytes from the encrypted channel, where r is the number of bytes
remaining in the buffer. If handshaking has not been previously
completed, handshaking also occurs at this stage. This method will also
respond appropriately with returning -1 (EOF) when the underlying
SSLEngine.isInboundDone()
, or when reading from the encrypted
channel returns -1 (EOF);
read
in interface SocketIF
buffer
- The buffer into which bytes are to be transferredjava.io.IOException
- Propagated exceptions from the underlying
SocketChannel.read(ByteBuffer buffer)
implementation.java.nio.BufferOverflowException
- If the underlying SSLEngineResult
has a status of BUFFER_OVERFLOW. As this should not happen in this
implementation, it can be considered serious and should be handledjava.nio.BufferUnderflowException
- If the underlying
SSLEngineResult
has a status of BUFFER_UNDERFLOW. As this should
not happen in this implementation, it can be considered serious and
should be handledpublic int write(java.nio.ByteBuffer buffer) throws java.io.IOException
SocketIF
SocketChannel.write(ByteBuffer buffer)
public void close() throws java.io.IOException
AbstractInterruptibleChannel.close()
. Before
closing the underlying SocketChannel
, attempts are made to
flush()
any encrypted data remaining in the encrypted buffer and
cleanly close the associated SSLEngine
.
Finally, we process
what we can via processHandshake()
before closing the underlying
SocketChannel
.
public boolean handshakePending()
SSLEngine
is still pending. This is called from the
application layer that invokes
AbstractSelector.send(SocketIF, ByteBuffer)
to correctly queue
data to be written.
handshakePending
in interface SocketIF
handshakePending()
public void setTaskPending(boolean taskPending)
SSLEngine
task pending, during an
SSL/TLS handshake. If the current socket implementation is processing
the pending tasks in the same thread, this method has no effect.
Otherwise in a multi-threaded implementation, this allows the
AbstractSelector
thread to know the status of the task, and
subsequently correctly process incoming requests (e.g. queueing data to
be written).
setTaskPending
in interface SocketIF
taskPending
- Set whether or not there is a SSLEngine
task
pending for the SSLEngine
associated with the underlying
SocketChannel
. Has no effect in a single threaded implementation.setTaskPending(boolean)