Package org.java_websocket
Class SSLSocketChannel
- java.lang.Object
-
- org.java_websocket.SSLSocketChannel
-
- All Implemented Interfaces:
java.io.Closeable
,java.lang.AutoCloseable
,java.nio.channels.ByteChannel
,java.nio.channels.Channel
,java.nio.channels.ReadableByteChannel
,java.nio.channels.WritableByteChannel
,ISSLChannel
,WrappedByteChannel
public class SSLSocketChannel extends java.lang.Object implements WrappedByteChannel, java.nio.channels.ByteChannel, ISSLChannel
A class that represents an SSL/TLS peer, and can be extended to create a client or a server. It makes use of the JSSE framework, and specifically theSSLEngine
logic, which is described by Oracle as "an advanced API, not appropriate for casual use", since it requires the user to implement much of the communication establishment procedure himself. More information about it can be found here: http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#SSLEngineSSLSocketChannel
implements the handshake protocol, required to establish a connection between two peers, which is common for both client and server and provides the abstractread(ByteBuffer)
andwrite(ByteBuffer)
(String)} methods, that need to be implemented by the specific SSL/TLS peer that is going to extend this class.
-
-
Field Summary
Fields Modifier and Type Field Description private javax.net.ssl.SSLEngine
engine
The engine which will be used for un-/wrapping of buffersprivate java.util.concurrent.ExecutorService
executor
Will be used to execute tasks that may emerge during handshake in parallel with the server's main thread.private org.slf4j.Logger
log
Logger instanceprivate java.nio.ByteBuffer
myAppData
Will contain this peer's application data in plaintext, that will be later encrypted usingSSLEngine.wrap(ByteBuffer, ByteBuffer)
and sent to the other peer.private java.nio.ByteBuffer
myNetData
Will contain this peer's encrypted data, that will be generated afterSSLEngine.wrap(ByteBuffer, ByteBuffer)
is applied onmyAppData
.private java.nio.ByteBuffer
peerAppData
Will contain the other peer's (decrypted) application data.private java.nio.ByteBuffer
peerNetData
Will contain the other peer's encrypted data.private java.nio.channels.SocketChannel
socketChannel
The underlying socket channel
-
Constructor Summary
Constructors Constructor Description SSLSocketChannel(java.nio.channels.SocketChannel inputSocketChannel, javax.net.ssl.SSLEngine inputEngine, java.util.concurrent.ExecutorService inputExecutor, java.nio.channels.SelectionKey key)
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description void
close()
private void
closeConnection()
This method should be called when this peer wants to explicitly close the connection or when a close message has arrived from the other peer, in order to provide an orderly shutdown.private boolean
doHandshake()
Implements the handshake protocol between two peers, required for the establishment of the SSL/TLS connection.private java.nio.ByteBuffer
enlargeApplicationBuffer(java.nio.ByteBuffer buffer)
Enlarging a packet buffer (peerAppData or myAppData)private java.nio.ByteBuffer
enlargeBuffer(java.nio.ByteBuffer buffer, int sessionProposedCapacity)
ComparessessionProposedCapacity
with buffer's capacity.
private java.nio.ByteBuffer
enlargePacketBuffer(java.nio.ByteBuffer buffer)
Enlarging a packet buffer (peerNetData or myNetData)javax.net.ssl.SSLEngine
getSSLEngine()
Get the ssl engine used for the de- and encryption of the communication.private java.nio.ByteBuffer
handleBufferUnderflow(java.nio.ByteBuffer buffer)
HandlesSSLEngineResult.Status.BUFFER_UNDERFLOW
.private void
handleEndOfStream()
In addition to orderly shutdowns, an unorderly shutdown may occur, when the transport link (socket channel) is severed before close messages are exchanged.boolean
isBlocking()
This function returns the blocking state of the channelboolean
isNeedRead()
returns whether readMore should be called to fetch data which has been decoded but not yet been returned.boolean
isNeedWrite()
returns whether writeMore should be called write additional data.boolean
isOpen()
int
read(java.nio.ByteBuffer dst)
int
readMore(java.nio.ByteBuffer dst)
This function does not read data from the underlying channel at all.int
write(java.nio.ByteBuffer output)
void
writeMore()
Gets called whenWrappedByteChannel.isNeedWrite()
()} requires a additional rite
-
-
-
Field Detail
-
log
private final org.slf4j.Logger log
Logger instance- Since:
- 1.4.0
-
socketChannel
private final java.nio.channels.SocketChannel socketChannel
The underlying socket channel
-
engine
private final javax.net.ssl.SSLEngine engine
The engine which will be used for un-/wrapping of buffers
-
myAppData
private java.nio.ByteBuffer myAppData
Will contain this peer's application data in plaintext, that will be later encrypted usingSSLEngine.wrap(ByteBuffer, ByteBuffer)
and sent to the other peer. This buffer can typically be of any size, as long as it is large enough to contain this peer's outgoing messages. If this peer tries to send a message bigger than buffer's capacity aBufferOverflowException
will be thrown.
-
myNetData
private java.nio.ByteBuffer myNetData
Will contain this peer's encrypted data, that will be generated afterSSLEngine.wrap(ByteBuffer, ByteBuffer)
is applied onmyAppData
. It should be initialized usingSSLSession.getPacketBufferSize()
, which returns the size up to which, SSL/TLS packets will be generated from the engine under a session. All SSLEngine network buffers should be sized at least this large to avoid insufficient space problems when performing wrap and unwrap calls.
-
peerAppData
private java.nio.ByteBuffer peerAppData
Will contain the other peer's (decrypted) application data. It must be large enough to hold the application data from any peer. Can be initialized withSSLSession.getApplicationBufferSize()
for an estimation of the other peer's application data and should be enlarged if this size is not enough.
-
peerNetData
private java.nio.ByteBuffer peerNetData
Will contain the other peer's encrypted data. The SSL/TLS protocols specify that implementations should produce packets containing at most 16 KB of plaintext, so a buffer sized to this value should normally cause no capacity problems. However, some implementations violate the specification and generate large records up to 32 KB. If theSSLEngine.unwrap(ByteBuffer, ByteBuffer)
detects large inbound packets, the buffer sizes returned by SSLSession will be updated dynamically, so the this peer should check for overflow conditions and enlarge the buffer using the session's (updated) buffer size.
-
executor
private java.util.concurrent.ExecutorService executor
Will be used to execute tasks that may emerge during handshake in parallel with the server's main thread.
-
-
Method Detail
-
read
public int read(java.nio.ByteBuffer dst) throws java.io.IOException
- Specified by:
read
in interfacejava.nio.channels.ReadableByteChannel
- Throws:
java.io.IOException
-
write
public int write(java.nio.ByteBuffer output) throws java.io.IOException
- Specified by:
write
in interfacejava.nio.channels.WritableByteChannel
- Throws:
java.io.IOException
-
doHandshake
private boolean doHandshake() throws java.io.IOException
Implements the handshake protocol between two peers, required for the establishment of the SSL/TLS connection. During the handshake, encryption configuration information - such as the list of available cipher suites - will be exchanged and if the handshake is successful will lead to an established SSL/TLS session.- 1. wrap: ClientHello
- 2. unwrap: ServerHello/Cert/ServerHelloDone
- 3. wrap: ClientKeyExchange
- 4. wrap: ChangeCipherSpec
- 5. wrap: Finished
- 6. unwrap: ChangeCipherSpec
- 7. unwrap: Finished
- Returns:
- True if the connection handshake was successful or false if an error occurred.
- Throws:
java.io.IOException
- - if an error occurs during read/write to the socket channel.
-
enlargePacketBuffer
private java.nio.ByteBuffer enlargePacketBuffer(java.nio.ByteBuffer buffer)
Enlarging a packet buffer (peerNetData or myNetData)- Parameters:
buffer
- the buffer to enlarge- Returns:
- the enlarged buffer
-
enlargeApplicationBuffer
private java.nio.ByteBuffer enlargeApplicationBuffer(java.nio.ByteBuffer buffer)
Enlarging a packet buffer (peerAppData or myAppData)- Parameters:
buffer
- the buffer to enlarge- Returns:
- the enlarged buffer
-
enlargeBuffer
private java.nio.ByteBuffer enlargeBuffer(java.nio.ByteBuffer buffer, int sessionProposedCapacity)
ComparessessionProposedCapacity
with buffer's capacity. If buffer's capacity is smaller, returns a buffer with the proposed capacity. If it's equal or larger, returns a buffer with capacity twice the size of the initial one.
- Parameters:
buffer
- - the buffer to be enlarged.sessionProposedCapacity
- - the minimum size of the new buffer, proposed bySSLSession
.- Returns:
- A new buffer with a larger capacity.
-
handleBufferUnderflow
private java.nio.ByteBuffer handleBufferUnderflow(java.nio.ByteBuffer buffer)
HandlesSSLEngineResult.Status.BUFFER_UNDERFLOW
. Will check if the buffer is already filled, and if there is no space problem will return the same buffer, so the client tries to read again. If the buffer is already filled will try to enlarge the buffer either to session's proposed size or to a larger capacity. A buffer underflow can happen only after an unwrap, so the buffer will always be a peerNetData buffer.- Parameters:
buffer
- - will always be peerNetData buffer.- Returns:
- The same buffer if there is no space problem or a new buffer with the same data but more space.
-
closeConnection
private void closeConnection() throws java.io.IOException
This method should be called when this peer wants to explicitly close the connection or when a close message has arrived from the other peer, in order to provide an orderly shutdown. It first callsSSLEngine.closeOutbound()
which prepares this peer to send its own close message and setsSSLEngine
to theNEED_WRAP
state. Then, it delegates the exchange of close messages to the handshake method and finally, it closes socket channel.- Throws:
java.io.IOException
- if an I/O error occurs to the socket channel.
-
handleEndOfStream
private void handleEndOfStream() throws java.io.IOException
In addition to orderly shutdowns, an unorderly shutdown may occur, when the transport link (socket channel) is severed before close messages are exchanged. This may happen by getting an -1 orIOException
when trying to read from the socket channel, or anIOException
when trying to write to it. In both casesSSLEngine.closeInbound()
should be called and then try to follow the standard procedure.- Throws:
java.io.IOException
- if an I/O error occurs to the socket channel.
-
isNeedWrite
public boolean isNeedWrite()
Description copied from interface:WrappedByteChannel
returns whether writeMore should be called write additional data.- Specified by:
isNeedWrite
in interfaceWrappedByteChannel
- Returns:
- is a additional write needed
-
writeMore
public void writeMore() throws java.io.IOException
Description copied from interface:WrappedByteChannel
Gets called whenWrappedByteChannel.isNeedWrite()
()} requires a additional rite- Specified by:
writeMore
in interfaceWrappedByteChannel
- Throws:
java.io.IOException
- may be thrown due to an error while writing
-
isNeedRead
public boolean isNeedRead()
Description copied from interface:WrappedByteChannel
returns whether readMore should be called to fetch data which has been decoded but not yet been returned.- Specified by:
isNeedRead
in interfaceWrappedByteChannel
- Returns:
- is a additional read needed
- See Also:
ReadableByteChannel.read(ByteBuffer)
,WrappedByteChannel.readMore(ByteBuffer)
-
readMore
public int readMore(java.nio.ByteBuffer dst) throws java.io.IOException
Description copied from interface:WrappedByteChannel
This function does not read data from the underlying channel at all. It is just a way to fetch data which has already be received or decoded but was but was not yet returned to the user. This could be the case when the decoded data did not fit into the buffer the user passed toReadableByteChannel.read(ByteBuffer)
.- Specified by:
readMore
in interfaceWrappedByteChannel
- Parameters:
dst
- the destiny of the read- Returns:
- the amount of remaining data
- Throws:
java.io.IOException
- when a error occurred during unwrapping
-
isBlocking
public boolean isBlocking()
Description copied from interface:WrappedByteChannel
This function returns the blocking state of the channel- Specified by:
isBlocking
in interfaceWrappedByteChannel
- Returns:
- is the channel blocking
-
isOpen
public boolean isOpen()
- Specified by:
isOpen
in interfacejava.nio.channels.Channel
-
close
public void close() throws java.io.IOException
- Specified by:
close
in interfacejava.lang.AutoCloseable
- Specified by:
close
in interfacejava.nio.channels.Channel
- Specified by:
close
in interfacejava.io.Closeable
- Throws:
java.io.IOException
-
getSSLEngine
public javax.net.ssl.SSLEngine getSSLEngine()
Description copied from interface:ISSLChannel
Get the ssl engine used for the de- and encryption of the communication.- Specified by:
getSSLEngine
in interfaceISSLChannel
- Returns:
- the ssl engine of this channel
-
-