in sshd-core/src/main/java/org/apache/sshd/client/SshClient.java [555:651]
protected ConnectFuture doConnect(
HostConfigEntry hostConfig, List<HostConfigEntry> jumps,
AttributeRepository context, SocketAddress localAddress)
throws IOException {
Objects.requireNonNull(hostConfig, "No host configuration");
String host = ValidateUtils.checkNotNullAndNotEmpty(hostConfig.getHostName(), "No target host");
int port = hostConfig.getPort();
ValidateUtils.checkTrue(port > 0, "Invalid port: %d", port);
Collection<String> hostIds = hostConfig.getIdentities();
Collection<PathResource> idFiles = GenericUtils.stream(hostIds)
.map(Paths::get)
.map(PathResource::new)
.collect(Collectors.toCollection(() -> new ArrayList<>(hostIds.size())));
KeyIdentityProvider keys = preloadClientIdentities(idFiles);
String username = hostConfig.getUsername();
InetSocketAddress targetAddress = new InetSocketAddress(hostConfig.getHostName(), hostConfig.getPort());
if (GenericUtils.isNotEmpty(jumps)) {
ConnectFuture connectFuture = new DefaultConnectFuture(username + "@" + targetAddress, null);
HostConfigEntry jump = jumps.remove(0);
ConnectFuture f1 = doConnect(jump, jumps, context, null);
AtomicReference<Cancellable> toCancel = new AtomicReference<>(f1);
connectFuture.addListener(c -> {
if (!c.isCanceled()) {
return;
}
Cancellable inner = toCancel.get();
if (inner == null) {
return;
}
CancelFuture cancellation = inner.cancel();
if (cancellation == null) {
return;
}
cancellation.addListener(cf -> {
if (cf.isDone()) {
c.getCancellation().setCanceled();
}
});
});
f1.addListener(f2 -> {
if (f2.isConnected()) {
ClientSession proxySession = f2.getClientSession();
try {
if (connectFuture.isCanceled()) {
proxySession.close(true);
}
AuthFuture auth = proxySession.auth();
toCancel.set(auth);
auth.addListener(f3 -> {
if (f3.isSuccess()) {
try {
SshdSocketAddress address
= new SshdSocketAddress(hostConfig.getHostName(), hostConfig.getPort());
ExplicitPortForwardingTracker tracker = proxySession
.createLocalPortForwardingTracker(SshdSocketAddress.LOCALHOST_ADDRESS, address);
SshdSocketAddress bound = tracker.getBoundAddress();
ConnectFuture f4 = doConnect(hostConfig.getUsername(), bound.toInetSocketAddress(),
context, localAddress, keys, hostConfig);
toCancel.set(f4);
if (connectFuture.isCanceled()) {
f4.cancel();
}
f4.addListener(f5 -> {
if (f5.isConnected()) {
ClientSession clientSession = f5.getClientSession();
clientSession.setAttribute(TARGET_SERVER, address);
connectFuture.setSession(clientSession);
proxySession.addCloseFutureListener(f6 -> clientSession.close(true));
clientSession.addCloseFutureListener(f6 -> proxySession.close(true));
} else {
proxySession.close(true);
connectFuture.setException(f5.getException());
}
});
} catch (IOException e) {
proxySession.close(true);
connectFuture.setException(e);
}
} else {
proxySession.close(true);
connectFuture.setException(f3.getException());
}
});
} catch (IOException e) {
proxySession.close(true);
connectFuture.setException(e);
}
} else {
connectFuture.setException(f2.getException());
}
});
return connectFuture;
} else {
return doConnect(hostConfig.getUsername(), new InetSocketAddress(host, port),
context, localAddress, keys, hostConfig);
}
}