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 the
SSLEnginelogic, 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#SSLEngineSSLSocketChannelimplements 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.SSLEngineengineThe engine which will be used for un-/wrapping of buffersprivate java.util.concurrent.ExecutorServiceexecutorWill be used to execute tasks that may emerge during handshake in parallel with the server's main thread.private org.slf4j.LoggerlogLogger instanceprivate java.nio.ByteBuffermyAppDataWill 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.ByteBuffermyNetDataWill contain this peer's encrypted data, that will be generated afterSSLEngine.wrap(ByteBuffer, ByteBuffer)is applied onmyAppData.private java.nio.ByteBufferpeerAppDataWill contain the other peer's (decrypted) application data.private java.nio.ByteBufferpeerNetDataWill contain the other peer's encrypted data.private java.nio.channels.SocketChannelsocketChannelThe 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 voidclose()private voidcloseConnection()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 booleandoHandshake()Implements the handshake protocol between two peers, required for the establishment of the SSL/TLS connection.private java.nio.ByteBufferenlargeApplicationBuffer(java.nio.ByteBuffer buffer)Enlarging a packet buffer (peerAppData or myAppData)private java.nio.ByteBufferenlargeBuffer(java.nio.ByteBuffer buffer, int sessionProposedCapacity)ComparessessionProposedCapacitywith buffer's capacity.private java.nio.ByteBufferenlargePacketBuffer(java.nio.ByteBuffer buffer)Enlarging a packet buffer (peerNetData or myNetData)javax.net.ssl.SSLEnginegetSSLEngine()Get the ssl engine used for the de- and encryption of the communication.private java.nio.ByteBufferhandleBufferUnderflow(java.nio.ByteBuffer buffer)HandlesSSLEngineResult.Status.BUFFER_UNDERFLOW.private voidhandleEndOfStream()In addition to orderly shutdowns, an unorderly shutdown may occur, when the transport link (socket channel) is severed before close messages are exchanged.booleanisBlocking()This function returns the blocking state of the channelbooleanisNeedRead()returns whether readMore should be called to fetch data which has been decoded but not yet been returned.booleanisNeedWrite()returns whether writeMore should be called write additional data.booleanisOpen()intread(java.nio.ByteBuffer dst)intreadMore(java.nio.ByteBuffer dst)This function does not read data from the underlying channel at all.intwrite(java.nio.ByteBuffer output)voidwriteMore()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 aBufferOverflowExceptionwill 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:
readin interfacejava.nio.channels.ReadableByteChannel- Throws:
java.io.IOException
-
write
public int write(java.nio.ByteBuffer output) throws java.io.IOException- Specified by:
writein interfacejava.nio.channels.WritableByteChannel- Throws:
java.io.IOException
-
doHandshake
private boolean doHandshake() throws java.io.IOExceptionImplements 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.
A typical handshake will usually contain the following steps:- 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)ComparessessionProposedCapacitywith 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.IOExceptionThis 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 setsSSLEngineto theNEED_WRAPstate. 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.IOExceptionIn 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 orIOExceptionwhen trying to read from the socket channel, or anIOExceptionwhen 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:WrappedByteChannelreturns whether writeMore should be called write additional data.- Specified by:
isNeedWritein interfaceWrappedByteChannel- Returns:
- is a additional write needed
-
writeMore
public void writeMore() throws java.io.IOExceptionDescription copied from interface:WrappedByteChannelGets called whenWrappedByteChannel.isNeedWrite()()} requires a additional rite- Specified by:
writeMorein interfaceWrappedByteChannel- Throws:
java.io.IOException- may be thrown due to an error while writing
-
isNeedRead
public boolean isNeedRead()
Description copied from interface:WrappedByteChannelreturns whether readMore should be called to fetch data which has been decoded but not yet been returned.- Specified by:
isNeedReadin 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.IOExceptionDescription copied from interface:WrappedByteChannelThis 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:
readMorein 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:WrappedByteChannelThis function returns the blocking state of the channel- Specified by:
isBlockingin interfaceWrappedByteChannel- Returns:
- is the channel blocking
-
isOpen
public boolean isOpen()
- Specified by:
isOpenin interfacejava.nio.channels.Channel
-
close
public void close() throws java.io.IOException- Specified by:
closein interfacejava.lang.AutoCloseable- Specified by:
closein interfacejava.nio.channels.Channel- Specified by:
closein interfacejava.io.Closeable- Throws:
java.io.IOException
-
getSSLEngine
public javax.net.ssl.SSLEngine getSSLEngine()
Description copied from interface:ISSLChannelGet the ssl engine used for the de- and encryption of the communication.- Specified by:
getSSLEnginein interfaceISSLChannel- Returns:
- the ssl engine of this channel
-
-