Top Description Fields Constructors Methods
org.java_websocket

public Class SSLSocketChannel

extends Object
implements WrappedByteChannel, ByteChannel, ISSLChannel
Class Inheritance
All Implemented Interfaces
org.java_websocket.interfaces.ISSLChannel, java.nio.channels.ByteChannel, java.nio.channels.WritableByteChannel, java.nio.channels.Channel, java.io.Closeable, java.lang.AutoCloseable, java.nio.channels.ReadableByteChannel, org.java_websocket.WrappedByteChannel
Imports
java.io.IOException, java.nio.BufferOverflowException, .ByteBuffer, java.nio.channels.ByteChannel, .SelectionKey, .SocketChannel, java.util.concurrent.ExecutorService, javax.net.ssl.SSLEngine, .SSLEngineResult, .SSLEngineResult.HandshakeStatus, .SSLException, .SSLSession, org.java_websocket.interfaces.ISSLChannel, org.java_websocket.util.ByteBufferUtils, org.slf4j.Logger, .LoggerFactory

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 SSLSocketChannel#read(ByteBuffer) and SSLSocketChannel#write(ByteBuffer) (String)} methods, that need to be implemented by the specific SSL/TLS peer that is going to extend this class.

Author
Alex Karnezis

Modified by marci4 to allow the usage as a ByteChannel

Permission for usage received at May 25, 2017 by Alex Karnezis

Field Summary

Modifier and TypeField and Description
private final SSLEngine
engine

The engine which will be used for un-/wrapping of buffers

private ExecutorService
executor

Will be used to execute tasks that may emerge during handshake in parallel with the server's main thread.

private final Logger
log

Logger instance

private ByteBuffer
myAppData

Will contain this peer's application data in plaintext, that will be later encrypted using SSLEngine#wrap(ByteBuffer, ByteBuffer) and sent to the other peer.

private ByteBuffer
myNetData

Will contain this peer's encrypted data, that will be generated after SSLEngine#wrap(ByteBuffer, ByteBuffer) is applied on SSLSocketChannel#myAppData.

private ByteBuffer
peerAppData

Will contain the other peer's (decrypted) application data.

private ByteBuffer
peerNetData

Will contain the other peer's encrypted data.

private final SocketChannel
socketChannel

The underlying socket channel

Constructor Summary

AccessConstructor and Description
public
SSLSocketChannel(SocketChannel inputSocketChannel, SSLEngine inputEngine, ExecutorService inputExecutor, SelectionKey key)

Method Summary

Modifier and TypeMethod and Description
public void
close()

Implements java.nio.channels.Channel.close.

Closes this channel.

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

Returns:

True if the connection handshake was successful or false if an error occurred.
doHandshake
()

Implements the handshake protocol between two peers, required for the establishment of the SSL/TLS connection.

private ByteBuffer

Returns:

the enlarged buffer
enlargeApplicationBuffer
(ByteBuffer
the buffer to enlarge
buffer
)

Enlarging a packet buffer (peerAppData or myAppData)

private ByteBuffer

Returns:

A new buffer with a larger capacity.
enlargeBuffer
(ByteBuffer
- the buffer to be enlarged.
buffer
,
int
- the minimum size of the new buffer, proposed by SSLSession.
sessionProposedCapacity
)

Compares sessionProposedCapacity with buffer's capacity.

private ByteBuffer

Returns:

the enlarged buffer
enlargePacketBuffer
(ByteBuffer
the buffer to enlarge
buffer
)

Enlarging a packet buffer (peerNetData or myNetData)

public SSLEngine
getSSLEngine()

Implements org.java_websocket.interfaces.ISSLChannel.getSSLEngine.

Get the ssl engine used for the de- and encryption of the communication.

private ByteBuffer

Returns:

The same buffer if there is no space problem or a new buffer with the same data but more space.
handleBufferUnderflow
(ByteBuffer
- will always be peerNetData buffer.
buffer
)

Handles SSLEngineResult.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.

public boolean
isBlocking()

Implements org.java_websocket.WrappedByteChannel.isBlocking.

This function returns the blocking state of the channel

public boolean
isNeedRead()

Implements org.java_websocket.WrappedByteChannel.isNeedRead.

returns whether readMore should be called to fetch data which has been decoded but not yet been returned.

public boolean
isNeedWrite()

Implements org.java_websocket.WrappedByteChannel.isNeedWrite.

returns whether writeMore should be called write additional data.

public boolean
isOpen()

Implements java.nio.channels.Channel.isOpen.

Tells whether or not this channel is open.

public synchronized int
read(ByteBuffer dst)

Implements java.nio.channels.ReadableByteChannel.read.

Reads a sequence of bytes from this channel into the given buffer.

public int
readMore(ByteBuffer dst)

Implements org.java_websocket.WrappedByteChannel.readMore.

This function does not read data from the underlying channel at all.

public synchronized int
write(ByteBuffer output)

Implements java.nio.channels.WritableByteChannel.write.

Writes a sequence of bytes to this channel from the given buffer.

public void
writeMore()

Implements org.java_websocket.WrappedByteChannel.writeMore.

Gets called when isNeedWrite() ()} requires a additional rite

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

engineback to summary
private final SSLEngine engine

The engine which will be used for un-/wrapping of buffers

executorback to summary
private ExecutorService executor

Will be used to execute tasks that may emerge during handshake in parallel with the server's main thread.

logback to summary
private final Logger log

Logger instance

Since
1.4.0
myAppDataback to summary
private ByteBuffer myAppData

Will contain this peer's application data in plaintext, that will be later encrypted using SSLEngine#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 a BufferOverflowException will be thrown.

myNetDataback to summary
private ByteBuffer myNetData

Will contain this peer's encrypted data, that will be generated after SSLEngine#wrap(ByteBuffer, ByteBuffer) is applied on SSLSocketChannel#myAppData. It should be initialized using SSLSession#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.

peerAppDataback to summary
private 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 with SSLSession#getApplicationBufferSize() for an estimation of the other peer's application data and should be enlarged if this size is not enough.

peerNetDataback to summary
private 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 the SSLEngine#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.

socketChannelback to summary
private final SocketChannel socketChannel

The underlying socket channel

Constructor Detail

SSLSocketChannelback to summary
public SSLSocketChannel(SocketChannel inputSocketChannel, SSLEngine inputEngine, ExecutorService inputExecutor, SelectionKey key) throws IOException

Method Detail

closeback to summary
public void close() throws IOException

Implements java.nio.channels.Channel.close.

Doc from java.nio.channels.Channel.close.

Closes this channel.

After a channel is closed, any further attempt to invoke I/O operations upon it will cause a ClosedChannelException to be thrown.

If this channel is already closed then invoking this method has no effect.

This method may be invoked at any time. If some other thread has already invoked it, however, then another invocation will block until the first invocation is complete, after which it will return without effect.

Annotations
@Override
Exceptions
IOException:
If an I/O error occurs
closeConnectionback to summary
private void closeConnection() throws 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 calls SSLEngine#closeOutbound() which prepares this peer to send its own close message and sets SSLEngine to the NEED_WRAP state. Then, it delegates the exchange of close messages to the handshake method and finally, it closes socket channel.

Exceptions
IOException:
if an I/O error occurs to the socket channel.
doHandshakeback to summary
private boolean doHandshake() throws 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.

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

Handshake is also used during the end of the session, in order to properly close the connection between the two peers. A proper connection close will typically include the one peer sending a CLOSE message to another, and then wait for the other's CLOSE message to close the transport link. The other peer from his perspective would read a CLOSE message from his peer and then enter the handshake procedure to send his own CLOSE message as well.

Returns:boolean

True if the connection handshake was successful or false if an error occurred.

Exceptions
IOException:
- if an error occurs during read/write to the socket channel.
enlargeApplicationBufferback to summary
private ByteBuffer enlargeApplicationBuffer(ByteBuffer buffer)

Enlarging a packet buffer (peerAppData or myAppData)

Parameters
buffer:ByteBuffer

the buffer to enlarge

Returns:ByteBuffer

the enlarged buffer

enlargeBufferback to summary
private ByteBuffer enlargeBuffer(ByteBuffer buffer, int sessionProposedCapacity)

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:ByteBuffer

- the buffer to be enlarged.

sessionProposedCapacity:int

- the minimum size of the new buffer, proposed by SSLSession.

Returns:ByteBuffer

A new buffer with a larger capacity.

enlargePacketBufferback to summary
private ByteBuffer enlargePacketBuffer(ByteBuffer buffer)

Enlarging a packet buffer (peerNetData or myNetData)

Parameters
buffer:ByteBuffer

the buffer to enlarge

Returns:ByteBuffer

the enlarged buffer

getSSLEngineback to summary
public SSLEngine getSSLEngine()

Implements org.java_websocket.interfaces.ISSLChannel.getSSLEngine.

Doc from org.java_websocket.interfaces.ISSLChannel.getSSLEngine.

Get the ssl engine used for the de- and encryption of the communication.

Annotations
@Override
handleBufferUnderflowback to summary
private ByteBuffer handleBufferUnderflow(ByteBuffer buffer)

Handles SSLEngineResult.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:ByteBuffer

- will always be peerNetData buffer.

Returns:ByteBuffer

The same buffer if there is no space problem or a new buffer with the same data but more space.

handleEndOfStreamback to summary
private void handleEndOfStream() throws 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 or IOException when trying to read from the socket channel, or an IOException when trying to write to it. In both cases SSLEngine#closeInbound() should be called and then try to follow the standard procedure.

Exceptions
IOException:
if an I/O error occurs to the socket channel.
isBlockingback to summary
public boolean isBlocking()

Implements org.java_websocket.WrappedByteChannel.isBlocking.

Doc from org.java_websocket.WrappedByteChannel.isBlocking.

This function returns the blocking state of the channel

Annotations
@Override
isNeedReadback to summary
public boolean isNeedRead()

Implements org.java_websocket.WrappedByteChannel.isNeedRead.

Doc from org.java_websocket.WrappedByteChannel.isNeedRead.

returns whether readMore should be called to fetch data which has been decoded but not yet been returned.

Annotations
@Override
isNeedWriteback to summary
public boolean isNeedWrite()

Implements org.java_websocket.WrappedByteChannel.isNeedWrite.

Doc from org.java_websocket.WrappedByteChannel.isNeedWrite.

returns whether writeMore should be called write additional data.

Annotations
@Override
isOpenback to summary
public boolean isOpen()

Implements java.nio.channels.Channel.isOpen.

Doc from java.nio.channels.Channel.isOpen.

Tells whether or not this channel is open.

Annotations
@Override
readback to summary
public synchronized int read(ByteBuffer dst) throws IOException

Implements java.nio.channels.ReadableByteChannel.read.

Doc from java.nio.channels.ReadableByteChannel.read.

Reads a sequence of bytes from this channel into the given buffer.

An attempt is made to read up to r bytes from the channel, where r is the number of bytes remaining in the buffer, that is, dst.remaining(), at the moment this method is invoked.

Suppose that a byte sequence of length n is read, where 0 <= n <= r. This byte sequence will be transferred into the buffer so that the first byte in the sequence is at index p and the last byte is at index p + n - 1, where p is the buffer's position at the moment this method is invoked. Upon return the buffer's position will be equal to p + n; its limit will not have changed.

A read operation might not fill the buffer, and in fact it might not read any bytes at all. Whether or not it does so depends upon the nature and state of the channel. A socket channel in non-blocking mode, for example, cannot read any more bytes than are immediately available from the socket's input buffer; similarly, a file channel cannot read any more bytes than remain in the file. It is guaranteed, however, that if a channel is in blocking mode and there is at least one byte remaining in the buffer then this method will block until at least one byte is read.

This method may be invoked at any time. If another thread has already initiated a read operation upon this channel, however, then an invocation of this method will block until the first operation is complete.

Annotations
@Override
Exceptions
IOException:
If some other I/O error occurs
readMoreback to summary
public int readMore(ByteBuffer dst) throws IOException

Implements org.java_websocket.WrappedByteChannel.readMore.

Doc from org.java_websocket.WrappedByteChannel.readMore.

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 to read(ByteBuffer).

Annotations
@Override
Exceptions
IOException:
when a error occurred during unwrapping
writeback to summary
public synchronized int write(ByteBuffer output) throws IOException

Implements java.nio.channels.WritableByteChannel.write.

Doc from java.nio.channels.WritableByteChannel.write.

Writes a sequence of bytes to this channel from the given buffer.

An attempt is made to write up to r bytes to the channel, where r is the number of bytes remaining in the buffer, that is, src.remaining(), at the moment this method is invoked.

Suppose that a byte sequence of length n is written, where 0 <= n <= r. This byte sequence will be transferred from the buffer starting at index p, where p is the buffer's position at the moment this method is invoked; the index of the last byte written will be p + n - 1. Upon return the buffer's position will be equal to p + n; its limit will not have changed.

Unless otherwise specified, a write operation will return only after writing all of the r requested bytes. Some types of channels, depending upon their state, may write only some of the bytes or possibly none at all. A socket channel in non-blocking mode, for example, cannot write any more bytes than are free in the socket's output buffer.

This method may be invoked at any time. If another thread has already initiated a write operation upon this channel, however, then an invocation of this method will block until the first operation is complete.

Annotations
@Override
Exceptions
IOException:
If some other I/O error occurs
writeMoreback to summary
public void writeMore() throws IOException

Implements org.java_websocket.WrappedByteChannel.writeMore.

Doc from org.java_websocket.WrappedByteChannel.writeMore.

Gets called when isNeedWrite() ()} requires a additional rite

Annotations
@Override
Exceptions
IOException:
may be thrown due to an error while writing