Top Description Fields Constructors Methods
org.apache.sshd.common.session.helpers

public Class KeyExchangeMessageHandler

extends Object
Class Inheritance
Imports
java.io.IOException, java.net.ProtocolException, java.security.GeneralSecurityException, java.util.AbstractMap.SimpleImmutableEntry, .ArrayList, .List, .Objects, .Queue, java.util.concurrent.ConcurrentLinkedQueue, .ExecutorService, .TimeUnit, java.util.concurrent.atomic.AtomicBoolean, .AtomicReference, java.util.concurrent.locks.ReentrantReadWriteLock, java.util.function.Supplier, org.apache.sshd.common.SshConstants, .SshException, org.apache.sshd.common.future.DefaultKeyExchangeFuture, org.apache.sshd.common.io.AbstractIoWriteFuture, .IoWriteFuture, org.apache.sshd.common.kex.KexState, org.apache.sshd.common.util.ExceptionUtils, .ValidateUtils, org.apache.sshd.common.util.buffer.Buffer, org.apache.sshd.common.util.threads.ThreadUtils, org.slf4j.Logger

Manages SSH message sending during a key exchange. RFC 4253 specifies that during a key exchange, no high-level messages are to be sent, but a receiver must be able to deal with messages "in flight" until the peer's SshConstants#SSH_MSG_KEXINIT message is received.

Apache MINA sshd queues up high-level messages that threads try to send while a key exchange is ongoing, and sends them once the key exchange is done. Sending queued messages may make the peer re-trigger a new key exchange, in which case sending queued messages stops and is resumed at the end of the new key exchange.

See Also
RFC 4253

Field Summary

Modifier and TypeField and Description
protected static ExecutorService
flushRunner

An ExecutorService used to flush the queue asynchronously.

protected final AtomicBoolean
kexFlushed

Indicates that all pending packets have been flushed.

protected final AtomicReference<DefaultKeyExchangeFuture>
kexFlushedFuture

Never null.

protected final ReentrantReadWriteLock
lock

We need the flushing thread to have priority over writing threads.

protected final Logger
log

The Logger to use.

protected final Queue<PendingWriteFuture>
pendingPackets

Queues up high-level packets written during an ongoing key exchange.

protected final AbstractSession
protected final AtomicBoolean
shutDown

Indicates that the handler has been shut down.

Constructor Summary

AccessConstructor and Description
public
KeyExchangeMessageHandler(AbstractSession
AbstractSession the new instance belongs to
session
,
Logger
Logger to use for writing log messages
log
)

Creates a new KeyExchangeMessageHandler for the given session, using the given Logger.

Method Summary

Modifier and TypeMethod and Description
private void
protected PendingWriteFuture

Returns:

the enqueued PendingWriteFuture
enqueuePendingPacket
(int
the SSH command from the buffer
cmd
,
Buffer
the Buffer containing the packet to be sent
buffer
)

Enqueues a packet to be written once a running key exchange terminates.

protected void
flushQueue(DefaultKeyExchangeFuture
the future obtained from getFlushedFuture; will be fulfilled once all pending packets have been written
flushDone
)

Flushes all packets enqueued while a key exchange was ongoing.

public DefaultKeyExchangeFuture

Returns:

the previous DefaultKeyExchangeFuture indicating whether all pending packets were flushed.
initNewKeyExchange
()

Initializes the state for a new key exchange.

protected boolean

Returns:

true if the thread may be blocked; false if the packet written must be queued without blocking the thread
isBlockAllowed
(int
SSH command of the buffer to be written
cmd
)

Tells whether the calling thread may be blocked in writePacket(Buffer, long, TimeUnit).

public void
shutdown()

Pretends all pending packets had been written.

public AbstractMap.SimpleImmutableEntry<Integer, DefaultKeyExchangeFuture>

Returns:

the current DefaultKeyExchangeFuture and the number of currently pending packets
terminateKeyExchange
()

To be called when the key exchange is done.

public void
public <V> V
updateState(Supplier<V> update)

protected IoWriteFuture

Returns:

an IoWriteFuture that will be fulfilled once the packet has indeed been written.
writeOrEnqueue
(int
SSH command from the buffer
cmd
,
Buffer
Buffer containing the packet to write
buffer
,
long
number of TimeUnits to wait at most if the calling thread is blocked
timeout
,
TimeUnit
TimeUnit of timeout
unit
)

Writes an SSH packet.

public IoWriteFuture

Returns:

an IoWriteFuture that will be fulfilled once the packet has indeed been written.
writePacket
(Buffer
packet to write
buffer
,
long
number of TimeUnits to wait at most if the calling thread is blocked
timeout
,
TimeUnit
TimeUnit of timeout
unit
)

Writes a packet.

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

flushRunnerback to summary
protected static ExecutorService flushRunner

An ExecutorService used to flush the queue asynchronously.

See Also
flushQueue(DefaultKeyExchangeFuture)
kexFlushedback to summary
protected final AtomicBoolean kexFlushed

Indicates that all pending packets have been flushed. Set to true by the flushing thread, or at the end of KEX if there are no packets to be flushed. Set to false when a new KEX starts. Initially true.

kexFlushedFutureback to summary
protected final AtomicReference<DefaultKeyExchangeFuture> kexFlushedFuture

Never null. Used to block some threads when writing packets while pending packets are still being flushed at the end of a KEX to avoid overrunning the flushing thread. Always set, initially fulfilled. At the beginning of a KEX a new future is installed, which is fulfilled at the end of the KEX once there are no more pending packets to be flushed.

lockback to summary
protected final ReentrantReadWriteLock lock

We need the flushing thread to have priority over writing threads. So we use a lock that favors writers over readers, and any state updates and the flushing thread are writers, while writePacket() is a reader.

logback to summary
protected final Logger log

The Logger to use.

pendingPacketsback to summary
protected final Queue<PendingWriteFuture> pendingPackets

Queues up high-level packets written during an ongoing key exchange.

sessionback to summary
protected final AbstractSession session

The AbstractSession this KeyExchangeMessageHandler belongs to.

shutDownback to summary
protected final AtomicBoolean shutDown

Indicates that the handler has been shut down.

Constructor Detail

KeyExchangeMessageHandlerback to summary
public KeyExchangeMessageHandler(AbstractSession session, Logger log)

Creates a new KeyExchangeMessageHandler for the given session, using the given Logger.

Parameters
session:AbstractSession

AbstractSession the new instance belongs to

log:Logger

Logger to use for writing log messages

Method Detail

drainQueueToback to summary
private void drainQueueTo(List<AbstractMap.SimpleImmutableEntry<PendingWriteFuture, IoWriteFuture>> pendingAborted, IoWriteFuture aborted)
enqueuePendingPacketback to summary
protected PendingWriteFuture enqueuePendingPacket(int cmd, Buffer buffer)

Enqueues a packet to be written once a running key exchange terminates.

Parameters
cmd:int

the SSH command from the buffer

buffer:Buffer

the Buffer containing the packet to be sent

Returns:PendingWriteFuture

the enqueued PendingWriteFuture

flushQueueback to summary
protected void flushQueue(DefaultKeyExchangeFuture flushDone)

Flushes all packets enqueued while a key exchange was ongoing. If writing the pending packets triggers a new key exchange, flushing is stopped and is to be resumed by another call to this method when the new key exchange is done.

Parameters
flushDone:DefaultKeyExchangeFuture

the future obtained from getFlushedFuture; will be fulfilled once all pending packets have been written

initNewKeyExchangeback to summary
public DefaultKeyExchangeFuture initNewKeyExchange()

Initializes the state for a new key exchange. allPacketsFlushed will be false, and a new future to be fulfilled when all queued packets will be flushed once the key exchange is done is set. The currently set future from an earlier key exchange is returned. The returned future may or may not be fulfilled; if it isn't, there are still left-over pending packets to write from the previous key exchange, which will be written once the new key exchange flushes pending packets.

Returns:DefaultKeyExchangeFuture

the previous DefaultKeyExchangeFuture indicating whether all pending packets were flushed.

isBlockAllowedback to summary
protected boolean isBlockAllowed(int cmd)

Tells whether the calling thread may be blocked in writePacket(Buffer, long, TimeUnit). This implementation blocks writes of channel data packets unless written by an internal thread.

Typically an internal thread is one of the reading threads of Apache MINA sshd handling an SSH protocol message: it's holding the AbstractSession#decodeLock; blocking it would mean we couldn't handle any other incoming message, not even disconnections or another key exchange triggered by having lots of data queued.

Parameters
cmd:int

SSH command of the buffer to be written

Returns:boolean

true if the thread may be blocked; false if the packet written must be queued without blocking the thread

shutdownback to summary
public void shutdown()

Pretends all pending packets had been written. To be called when the AbstractSession closes.

terminateKeyExchangeback to summary
public AbstractMap.SimpleImmutableEntry<Integer, DefaultKeyExchangeFuture> terminateKeyExchange()

To be called when the key exchange is done. If there are any pending packets, returns a future that will be fulfilled when flushQueue(DefaultKeyExchangeFuture) with that future as argument has flushed all pending packets, if there are any.

Returns:AbstractMap.SimpleImmutableEntry<Integer, DefaultKeyExchangeFuture>

the current DefaultKeyExchangeFuture and the number of currently pending packets

updateStateback to summary
public void updateState(Runnable update)
updateStateback to summary
public <V> V updateState(Supplier<V> update)
writeOrEnqueueback to summary
protected IoWriteFuture writeOrEnqueue(int cmd, Buffer buffer, long timeout, TimeUnit unit) throws IOException

Writes an SSH packet. If no KEX is ongoing and there are no pending packets queued to be written after KEX, the buffer is written directly. Otherwise, the write is enqueued or the calling thread is blocked until all pending packets have been written, depending on the result of isBlockAllowed(int). If the calling thread holds the monitor of the session's AbstractSession#getFutureLock(), it is never blocked and the write is queued.

If timeout <= 0 or unit == null, a time-out of "forever" is assumed. Note that a timeout applies only if the calling thread is blocked.

Parameters
cmd:int

SSH command from the buffer

buffer:Buffer

Buffer containing the packet to write

timeout:long

number of TimeUnits to wait at most if the calling thread is blocked

unit:TimeUnit

TimeUnit of timeout

Returns:IoWriteFuture

an IoWriteFuture that will be fulfilled once the packet has indeed been written.

Exceptions
IOException:
if an error occurs
writePacketback to summary
public IoWriteFuture writePacket(Buffer buffer, long timeout, TimeUnit unit) throws IOException

Writes a packet. If a key exchange is ongoing, only low-level messages are written directly; all other messages are queued and will be written once flushQueue(DefaultKeyExchangeFuture) is called when the key exchange is done. Packets written while there are still pending packets to be flushed will either be queued, too, or the calling thread will be blocked with the given timeout until all packets have been flushed. Whether a write will be blocked is determined by isBlockAllowed(int).

If a packet was written, a key exchange may be triggered via AbstractSession#checkRekey().

If timeout <= 0 or unit == null, a time-out of "forever" is assumed. Note that a timeout applies only if the calling thread is blocked.

Parameters
buffer:Buffer

packet to write

timeout:long

number of TimeUnits to wait at most if the calling thread is blocked

unit:TimeUnit

TimeUnit of timeout

Returns:IoWriteFuture

an IoWriteFuture that will be fulfilled once the packet has indeed been written.

Exceptions
IOException:
if an error occurs