Package org.java_websocket
Class SSLSocketChannel
java.lang.Object
org.java_websocket.SSLSocketChannel
- All Implemented Interfaces:
Closeable
,AutoCloseable
,ByteChannel
,Channel
,ReadableByteChannel
,WritableByteChannel
,ISSLChannel
,WrappedByteChannel
public class SSLSocketChannel
extends Object
implements WrappedByteChannel, 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 SSLEngine
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#SSLEngine
SSLSocketChannel
implements the handshake protocol, required to establish a connection
between two peers, which is common for both client and server and provides the abstract read(ByteBuffer)
and write(ByteBuffer)
(String)}
methods, that need to be implemented by the specific SSL/TLS peer that is going to extend this
class.
-
Field Summary
FieldsModifier and TypeFieldDescriptionprivate final SSLEngine
The engine which will be used for un-/wrapping of buffersprivate ExecutorService
Will be used to execute tasks that may emerge during handshake in parallel with the server's main thread.private final org.slf4j.Logger
Logger instanceprivate ByteBuffer
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 ByteBuffer
Will contain this peer's encrypted data, that will be generated afterSSLEngine.wrap(ByteBuffer, ByteBuffer)
is applied onmyAppData
.private ByteBuffer
Will contain the other peer's (decrypted) application data.private ByteBuffer
Will contain the other peer's encrypted data.private final SocketChannel
The underlying socket channel -
Constructor Summary
ConstructorsConstructorDescriptionSSLSocketChannel
(SocketChannel inputSocketChannel, SSLEngine inputEngine, ExecutorService inputExecutor, SelectionKey key) -
Method Summary
Modifier and TypeMethodDescriptionvoid
close()
private void
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
Implements the handshake protocol between two peers, required for the establishment of the SSL/TLS connection.private ByteBuffer
enlargeApplicationBuffer
(ByteBuffer buffer) Enlarging a packet buffer (peerAppData or myAppData)private ByteBuffer
enlargeBuffer
(ByteBuffer buffer, int sessionProposedCapacity) Compares sessionProposedCapacity with buffer's capacity.private ByteBuffer
enlargePacketBuffer
(ByteBuffer buffer) Enlarging a packet buffer (peerNetData or myNetData)Get the ssl engine used for the de- and encryption of the communication.private ByteBuffer
handleBufferUnderflow
(ByteBuffer buffer) private void
In addition to orderly shutdowns, an unorderly shutdown may occur, when the transport link (socket channel) is severed before close messages are exchanged.boolean
This function returns the blocking state of the channelboolean
returns whether readMore should be called to fetch data which has been decoded but not yet been returned.boolean
returns whether writeMore should be called write additional data.boolean
isOpen()
int
read
(ByteBuffer dst) int
readMore
(ByteBuffer dst) This function does not read data from the underlying channel at all.int
write
(ByteBuffer output) void
Gets called whenWrappedByteChannel.isNeedWrite()
()} requires a additional rite
-
Field Details
-
log
private final org.slf4j.Logger logLogger instance- Since:
- 1.4.0
-
socketChannel
The underlying socket channel -
engine
The engine which will be used for un-/wrapping of buffers -
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
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
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
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
Will be used to execute tasks that may emerge during handshake in parallel with the server's main thread.
-
-
Constructor Details
-
SSLSocketChannel
public SSLSocketChannel(SocketChannel inputSocketChannel, SSLEngine inputEngine, ExecutorService inputExecutor, SelectionKey key) throws IOException - Throws:
IOException
-
-
Method Details
-
read
- Specified by:
read
in interfaceReadableByteChannel
- Throws:
IOException
-
write
- Specified by:
write
in interfaceWritableByteChannel
- Throws:
IOException
-
doHandshake
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:
IOException
- - if an error occurs during read/write to the socket channel.
-
enlargePacketBuffer
Enlarging a packet buffer (peerNetData or myNetData)- Parameters:
buffer
- the buffer to enlarge- Returns:
- the enlarged buffer
-
enlargeApplicationBuffer
Enlarging a packet buffer (peerAppData or myAppData)- Parameters:
buffer
- the buffer to enlarge- Returns:
- the enlarged buffer
-
enlargeBuffer
Compares sessionProposedCapacity 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
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
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:
IOException
- if an I/O error occurs to the socket channel.
-
handleEndOfStream
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:
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
Description copied from interface:WrappedByteChannel
Gets called whenWrappedByteChannel.isNeedWrite()
()} requires a additional rite- Specified by:
writeMore
in interfaceWrappedByteChannel
- Throws:
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:
-
readMore
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:
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() -
close
- Specified by:
close
in interfaceAutoCloseable
- Specified by:
close
in interfaceChannel
- Specified by:
close
in interfaceCloseable
- Throws:
IOException
-
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
-