public abstract class AbstractSelector extends java.lang.Object implements java.lang.Runnable, TaskListener, HandshakeListener, TimeoutListener
Modifier and Type | Field and Description |
---|---|
protected java.net.InetAddress |
address
The address to listen at or connect
|
protected java.lang.String[] |
cipherSuits |
protected SocketContainer |
container
A SocketContainer to hold active socket instances
|
protected javax.net.ssl.SSLContext |
context
The associated SSLContext
|
protected boolean |
isClient
Whether this AbstractSelector is a client
|
protected static java.util.logging.Logger |
logger |
protected boolean |
needClientAuth
Whether this AbstractSelector needs clientAuth
|
protected java.util.HashMap<java.nio.channels.SocketChannel,java.util.List<java.nio.ByteBuffer>> |
pendingData
Maps a SocketChannel to a list of ByteBuffer instances
|
protected int |
port
The port to listen on or connect to
|
protected java.lang.String[] |
protocols |
protected java.nio.channels.Selector |
selector
The selector we'll be monitoring
|
protected boolean |
singleThreaded
Whether the SSLEngine tasks required run in the AbstractSelector thread
|
protected TaskWorker |
taskWorker
The underlying TaskWorker
|
protected TimeoutWorker |
toWorker
The underlying TimeoutWorker
|
protected boolean |
usingSSL
Whether we are using SSL/TLS
|
Constructor and Description |
---|
AbstractSelector(java.net.InetAddress address,
int port,
AbstractPacketWorker packetWorker,
boolean usingSSL,
boolean isClient,
boolean needClientAuth)
Create a new AbstractSelector instance.
|
Modifier and Type | Method and Description |
---|---|
protected abstract void |
accept(java.nio.channels.SelectionKey key)
Should accept incoming connections and bind new non-blocking
SocketIF instances to them. |
void |
addListener(PacketListener listener)
Pass-through method to allow registration of multiple
PacketListener s to the underlying AbstractPacketWorker . |
protected void |
closeSocket(SocketIF socket)
Closes the given
SocketIF . |
protected abstract void |
connect(java.nio.channels.SelectionKey key)
Should finish the connection to the server.
|
void |
handshakeComplete(SocketIF socket)
A handshake is completed on this socket, as such the socket is ready to
be used (reading and writing).
|
protected abstract void |
initConnection()
Initialize a connection.
|
protected void |
invalidateSession(SocketIF socket)
Invalidate the
SSLSession associated with the
provided SocketIF . |
boolean |
isRunning()
Check whether the
AbstractSelector is running. |
protected void |
read(java.nio.channels.SelectionKey key)
Reads data from the socket associated with the given
SelectionKey . |
void |
removeListener(PacketListener listener)
Pass-through method to allow de-registration of multiple
PacketListener s from the underlying AbstractPacketWorker . |
void |
run()
Initializes the selector, the worker threads, and initiates a select
procedure that can be either server or client based.
|
protected void |
send(SocketIF socket,
java.nio.ByteBuffer data)
Send an
ByteBuffer over the specified SocketIF . |
void |
setRunning(boolean running)
Set the running status of the
AbstractSelector . |
protected javax.net.ssl.SSLEngine |
setupEngine(java.lang.String peerHost,
int peerPort)
Sets up the underlying
SSLEngine to be used with a
SecureSocket implementation. |
void |
setupSSL(java.lang.String trustStoreLoc,
java.lang.String keyStoreLoc,
char[] tsPassPhrase,
char[] ksPassPhrase,
java.lang.String protocolsLoc,
java.lang.String cipherSuitesLoc)
If the server/client has been initialized to use SSL/TLS, this method is
used to setup and initialize the SSL/TLS required parameters.
|
void |
taskComplete(SocketIF socket)
A SSLEngine Task for a particular socket was completed by the TaskWorker.
|
void |
timeoutExpired(SocketIF socket)
The timeout on this socket has expired.
|
protected void |
write(java.nio.channels.SelectionKey key)
Writes data to the socket associated with the given
SelectionKey . |
protected static final java.util.logging.Logger logger
protected java.net.InetAddress address
protected int port
protected final java.util.HashMap<java.nio.channels.SocketChannel,java.util.List<java.nio.ByteBuffer>> pendingData
protected java.nio.channels.Selector selector
protected final boolean usingSSL
protected javax.net.ssl.SSLContext context
protected final SocketContainer container
protected final TaskWorker taskWorker
protected final TimeoutWorker toWorker
protected java.lang.String[] protocols
protected java.lang.String[] cipherSuits
protected final boolean isClient
protected final boolean needClientAuth
protected final boolean singleThreaded
public AbstractSelector(java.net.InetAddress address, int port, AbstractPacketWorker packetWorker, boolean usingSSL, boolean isClient, boolean needClientAuth)
address
- The address this selector will useport
- The port this selector will usepacketWorker
- The instance of packet worker to useusingSSL
- Whether we are using SSL/TLS
TaskWorker
thread.isClient
- If the current Selector implementation is a client
implementation (false indicates it is a server implementation).needClientAuth
- If the current implementation is a server
implementation, whether the client should also verify its authenticity
(i.e. sets up SSLEngine.setNeedClientAuth(true)).public void setupSSL(java.lang.String trustStoreLoc, java.lang.String keyStoreLoc, char[] tsPassPhrase, char[] ksPassPhrase, java.lang.String protocolsLoc, java.lang.String cipherSuitesLoc)
trustStoreLoc
- The location of the trustStore on the disk. The
trustore is *ALWAYS* required for a client implementation. For a server
implementation it is only required if needClientAuth is true, i.e. IFF
the client should also verify its authenticity; it can be null otherwise.keyStoreLoc
- The location of the keyStore on the disk. The keystore
is *ALWAYS* required for a server implementation. For a client
implementation it is only required if needClientAuth is true, i.e. IFF
the client should also verify its authenticity; it can be null otherwise.tsPassPhrase
- The passphrase to use with the trustStore or null if
the truststore is not required.ksPassPhrase
- The passphrase to use with the keyStore or null if
the keystore is not required.protocolsLoc
- The location of the file containing the SSL/TLS
protocols to be used by the client/server. WARNING: If null is passed, or
the file is not found, the default SSL/TLS protocols will be used
instead, as per SSLEngine.getEnabledProtocols().cipherSuitesLoc
- The location of the file containing the SSL/TLS
cipher suites to be used by the client/server. WARNING: If null is
passed, or the file is not found, the default SSL/TLS cipher suites will
be used instead, as per SSLEngine.getEnabledCipherSuites().protected javax.net.ssl.SSLEngine setupEngine(java.lang.String peerHost, int peerPort)
SSLEngine
to be used with a
SecureSocket
implementation.
The SSLEngine is initialized based on whether this instance is a server
or a client, whether we need clientAuth or not, and based on the provided
protocols and cipher suites provided in setupSSL(String trustStoreLoc, String keyStoreLoc, char[] tsPassPhrase,
char[] ksPassPhrase, String protocolsLoc, String cipherSuitesLoc)
. The
peerHost and peerPort parameters are passed as hints to the
SSLEngine
for engine re-usage purposes but can also be null.peerHost
- The peer host of the socketpeerPort
- The peer port of the socketpublic void run()
processChanges()
method. Upon shutdown, a
best-effort attempt is made to shutdown cleanly via the
shutdown()
method.run
in interface java.lang.Runnable
processChanges()
,
shutdown()
protected void invalidateSession(SocketIF socket)
SSLSession
associated with the
provided SocketIF
. The invalidation is queued as a pending change
where it is executed in a FIFO fashion along with any other pending
changes. This method could be periodically used via a
Timeout
to perform
SSL/TLS session rotation if needed.socket
- The socket whose underlying
SSLSession
should be invalidatesprocessChanges()
protected void send(SocketIF socket, java.nio.ByteBuffer data)
ByteBuffer
over the specified SocketIF
. This
method does not directly send the packets, but rather queues them for
sending as soon as possible. Data are subsequently written by setting
the associated SelectionKey
to SelectionKey.OP_WRITE. In case of
an SSL/TLS implementation and where the handshaking is not completed, the
SelectionKey is not changed until the handshake has finished.
socket
- The SocketIF to send the packet throughdata
- The ByteBuffer to send through the associated SocketIFprocessChanges()
protected abstract void initConnection() throws java.io.IOException
java.io.IOException
- Propagates all underlying IOExceptions as thrown, to
be handled by the application layer.run()
protected abstract void accept(java.nio.channels.SelectionKey key)
SocketIF
instances to them. If the server implementation is using
SSL/TLS, it should also set up the SSLEngine
, to be used.key
- The selection key with the underlying SocketChannel
to
be acceptedrun()
protected abstract void connect(java.nio.channels.SelectionKey key)
SocketIF
is
a secure socket. Finally, after the connection has been established, the
socket should be registered to the underlying Selector
, with a
SelectionKey
of OP_READ, signalling it is ready to read data.key
- The selection key with the underlying SocketChannel
that needs a connection finalization.protected void write(java.nio.channels.SelectionKey key)
SelectionKey
.
This method is ONLY called once we have set the SelectionKey
associated with the socket to OP_WRITE. It tries to write as much data as
possible before returning. Once there is no more data to be written on
this socket, it sets the SelectionKey
to OP_READ, disallowing any
further calls to this method until more data is available.key
- The SelectionKey whose associated socket we should write onprocessChanges()
,
send(ch.dermitza.securenio.socket.SocketIF, java.nio.ByteBuffer)
protected void read(java.nio.channels.SelectionKey key)
SelectionKey
. This method is called as soon as data is ready to
be read. It tries to read as much data as possible, handing bytes read to
the underlying AbstractPacketWorker
for reconstruction and
further processing. It also handles potential socket disconnections
and/or errors, upon which, it makes a best effort to close the socket
cleanly.key
- The SelectionKey whose associated socket we should read fromAbstractPacketWorker.addData(SocketIF, ByteBuffer, int)
,
closeSocket(ch.dermitza.securenio.socket.SocketIF)
protected void closeSocket(SocketIF socket)
SocketIF
. In doing that, it also removes any
potentially queued ChangeRequest
s not yet processed on that
socket, and also removes the socket from the underlying
SocketContainer
.
TODO: Only pending data is being removed. A correct implementation would
also remove all other pendingChanges instances. Alternatively, we should
check for closed sockets when processing changes
(processChanges()
) and not perform any changes if the
socket is closed.socket
- The socket to closeprocessChanges()
public boolean isRunning()
AbstractSelector
is running.public void setRunning(boolean running)
AbstractSelector
. If the running
status of the selector is set to false, the selector is interrupted in
order to cleanly shutdown by invoking Selector.wakeup()
.running
- Whether the AbstractSelector should run or notpublic void timeoutExpired(SocketIF socket)
timeoutExpired
in interface TimeoutListener
socket
- The socket of which its timeout has expiredpublic void taskComplete(SocketIF socket)
taskComplete
in interface TaskListener
socket
- The socket of which an SSLEngine task was completedSecureSocket
,
AbstractSelector
public void handshakeComplete(SocketIF socket)
handshakeComplete
in interface HandshakeListener
socket
- the socket of which its handshake is completedSecureSocket
,
AbstractSelector
public void addListener(PacketListener listener)
PacketListener
s to the underlying AbstractPacketWorker
.listener
- The listener to register to the underlying PacketWorkerpublic void removeListener(PacketListener listener)
PacketListener
s from the underlying AbstractPacketWorker
.listener
- The listener to unregister from the underlying
PacketWorker