in sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractConnectionService.java [733:824]
protected void channelOpen(Buffer buffer) throws Exception {
String type = buffer.getString();
long sender = buffer.getUInt();
long rwsize = buffer.getUInt();
long rmpsize = buffer.getUInt();
/*
* NOTE: the 'sender' is the identifier assigned by the remote side - the server in this case
*/
boolean debugEnabled = log.isDebugEnabled();
if (debugEnabled) {
log.debug("channelOpen({}) SSH_MSG_CHANNEL_OPEN sender={}, type={}, window-size={}, packet-size={}",
this, sender, type, rwsize, rmpsize);
}
if (isClosing()) {
// TODO add language tag configurable control
sendChannelOpenFailure(buffer, sender, SshConstants.SSH_OPEN_CONNECT_FAILED,
"Server is shutting down while attempting to open channel type=" + type, "");
return;
}
if (!isAllowMoreSessions()) {
// TODO add language tag configurable control
sendChannelOpenFailure(buffer, sender, SshConstants.SSH_OPEN_CONNECT_FAILED, "additional sessions disabled", "");
return;
}
Session session = getSession();
FactoryManager manager = Objects.requireNonNull(session.getFactoryManager(), "No factory manager");
Channel channel = ChannelFactory.createChannel(session, manager.getChannelFactories(), type);
if (channel == null) {
// TODO add language tag configurable control
sendChannelOpenFailure(buffer, sender,
SshConstants.SSH_OPEN_UNKNOWN_CHANNEL_TYPE, "Unsupported channel type: " + type, "");
return;
}
long channelId = registerChannel(channel);
channel.addChannelListener(new ChannelListener() {
@Override
public void channelOpenSuccess(Channel channel) {
// Do not rely on the OpenFuture. We must be sure that we get the SSH_MSG_CHANNEL_OPEN_CONFIRMATION out
// before anything else.
try {
LocalWindow window = channel.getLocalWindow();
if (debugEnabled) {
log.debug(
"channelOpenSuccess({}) send SSH_MSG_CHANNEL_OPEN_CONFIRMATION recipient={}, sender={}, window-size={}, packet-size={}",
channel, sender, channelId, window.getSize(), window.getPacketSize());
}
Buffer buf = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_OPEN_CONFIRMATION, Integer.SIZE);
buf.putUInt(sender); // remote (server side) identifier
buf.putUInt(channelId); // local (client side) identifier
buf.putUInt(window.getSize());
buf.putUInt(window.getPacketSize());
session.writePacket(buf);
} catch (IOException e) {
warn("channelOpenSuccess({}) {}: {}", AbstractConnectionService.this, e.getClass().getSimpleName(),
e.getMessage(), e);
session.exceptionCaught(e);
}
}
});
OpenFuture openFuture = channel.open(sender, rwsize, rmpsize, buffer);
openFuture.addListener(future -> {
try {
if (!future.isOpened()) {
int reasonCode = 0;
String message = "Generic error while opening channel: " + channelId;
Throwable exception = future.getException();
if (exception != null) {
if (exception instanceof SshChannelOpenException) {
reasonCode = ((SshChannelOpenException) exception).getReasonCode();
} else {
message = exception.getClass().getSimpleName() + " while opening channel: " + message;
}
} else {
log.warn("operationComplete({}) no exception on closed future={}",
AbstractConnectionService.this, future);
}
Buffer buf = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_OPEN_FAILURE, message.length() + Long.SIZE);
sendChannelOpenFailure(buf, sender, reasonCode, message, "");
}
} catch (IOException e) {
warn("operationComplete({}) {}: {}",
AbstractConnectionService.this, e.getClass().getSimpleName(), e.getMessage(), e);
session.exceptionCaught(e);
}
});
}