mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-14 03:35:37 +02:00
Support proxy connection for gateway without sftp or with MaxSession=1
Command proxy does not work if both the host and the gateway have MaxSession=1 (caused by 356657). Add support in JschConnection for a connection which has a session but isn't fully setup. Such a connection isn't considered open. And if it is opened after it already has a session without setupFully=false (default), then all setup setups are done. Also change that getProxyConnection returns null not a LocalConnection for a local command. This reduces the dependency on LocalConnection from within jsch.core.*. Change-Id: I64d05e69749d96248d2f40bd2db021d809cb04a9
This commit is contained in:
parent
b1903767f3
commit
95db103e5b
5 changed files with 106 additions and 57 deletions
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
org.eclipse.jdt.core.compiler.source=1.7
|
||||
|
|
|
@ -15,4 +15,4 @@ Bundle-ActivationPolicy: lazy
|
|||
Export-Package: org.eclipse.remote.internal.jsch.core;x-friends:="org.eclipse.remote.jsch.ui",
|
||||
org.eclipse.remote.internal.jsch.core.messages;x-internal:=true
|
||||
Bundle-Localization: plugin
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||
|
|
|
@ -27,14 +27,12 @@ import org.eclipse.osgi.util.NLS;
|
|||
import org.eclipse.remote.core.IRemoteConnection;
|
||||
import org.eclipse.remote.core.IRemoteConnectionChangeEvent;
|
||||
import org.eclipse.remote.core.IRemoteConnectionChangeListener;
|
||||
import org.eclipse.remote.core.IRemoteConnectionManager;
|
||||
import org.eclipse.remote.core.IRemoteConnectionWorkingCopy;
|
||||
import org.eclipse.remote.core.IRemoteFileManager;
|
||||
import org.eclipse.remote.core.IRemoteProcess;
|
||||
import org.eclipse.remote.core.IRemoteProcessBuilder;
|
||||
import org.eclipse.remote.core.IRemoteServices;
|
||||
import org.eclipse.remote.core.IUserAuthenticator;
|
||||
import org.eclipse.remote.core.RemoteServices;
|
||||
import org.eclipse.remote.core.exception.AddressInUseException;
|
||||
import org.eclipse.remote.core.exception.RemoteConnectionException;
|
||||
import org.eclipse.remote.core.exception.UnableToForwardPortException;
|
||||
|
@ -186,6 +184,7 @@ public class JSchConnection implements IRemoteConnection {
|
|||
private final List<Session> fSessions = new ArrayList<Session>();
|
||||
|
||||
private ChannelSftp fSftpChannel;
|
||||
private boolean isFullySetup; // including sftp channel and environment
|
||||
|
||||
public JSchConnection(String name, IRemoteServices services) {
|
||||
fRemoteServices = services;
|
||||
|
@ -590,23 +589,22 @@ public class JSchConnection implements IRemoteConnection {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the proxy connection. If no proxy is used it returns a local connection.
|
||||
* Gets the proxy connection. If no proxy connection is used it returns null.
|
||||
*
|
||||
* @return proxy connection
|
||||
*/
|
||||
public IRemoteConnection getProxyConnection() {
|
||||
public JSchConnection getProxyConnection() {
|
||||
String proxyConnectionName = getProxyConnectionName();
|
||||
if (proxyConnectionName.equals(EMPTY_STRING)) {
|
||||
return RemoteServices.getLocalServices().getConnectionManager().getConnection(
|
||||
IRemoteConnectionManager.LOCAL_CONNECTION_NAME);
|
||||
return null;
|
||||
}
|
||||
return fManager.getConnection(proxyConnectionName);
|
||||
return (JSchConnection) fManager.getConnection(proxyConnectionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the proxy connection name
|
||||
*
|
||||
* @return proxy connection name
|
||||
* @return proxy connection name. If no proxy is used returns an empty string. Never returns null.
|
||||
*/
|
||||
public String getProxyConnectionName() {
|
||||
return fAttributes.getAttribute(JSchConnectionAttributes.PROXYCONNECTION_ATTR, EMPTY_STRING);
|
||||
|
@ -699,6 +697,24 @@ public class JSchConnection implements IRemoteConnection {
|
|||
return fWorkingDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the connection has a valid open session. Doesn't check whether the connection is fully setup.
|
||||
*
|
||||
* @return true if a valid session is available.
|
||||
*/
|
||||
public boolean hasOpenSession() {
|
||||
boolean hasOpenSession = fSessions.size() > 0;
|
||||
if (hasOpenSession) {
|
||||
for (Session session : fSessions) {
|
||||
hasOpenSession &= session.isConnected();
|
||||
}
|
||||
}
|
||||
if (!hasOpenSession) {
|
||||
close(); // Cleanup if session is closed
|
||||
}
|
||||
return hasOpenSession;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
@ -706,16 +722,7 @@ public class JSchConnection implements IRemoteConnection {
|
|||
*/
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
boolean isOpen = fSessions.size() > 0;
|
||||
if (isOpen) {
|
||||
for (Session session : fSessions) {
|
||||
isOpen &= session.isConnected();
|
||||
}
|
||||
}
|
||||
if (!isOpen) {
|
||||
close(); // Cleanup if session is closed
|
||||
}
|
||||
return isOpen;
|
||||
return hasOpenSession() && isFullySetup;
|
||||
}
|
||||
|
||||
public boolean isPasswordAuth() {
|
||||
|
@ -869,16 +876,44 @@ public class JSchConnection implements IRemoteConnection {
|
|||
*/
|
||||
@Override
|
||||
public void open(IProgressMonitor monitor) throws RemoteConnectionException {
|
||||
if (!isOpen()) {
|
||||
checkIsConfigured();
|
||||
open(monitor, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open ssh connection without full setup (environment, sftp)
|
||||
*
|
||||
* @see org.eclipse.remote.core.IRemoteConnection#open()
|
||||
*
|
||||
* @param monitor
|
||||
* @throws RemoteConnectionException
|
||||
*/
|
||||
public void openMinimal(IProgressMonitor monitor) throws RemoteConnectionException {
|
||||
open(monitor, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.remote.core.IRemoteConnection#open()
|
||||
*
|
||||
* @param monitor
|
||||
* @param setupFully
|
||||
* open a full featured connection (environment query and sftp)
|
||||
* @throws RemoteConnectionException
|
||||
*/
|
||||
private void open(IProgressMonitor monitor, boolean setupFully) throws RemoteConnectionException {
|
||||
SubMonitor subMon = SubMonitor.convert(monitor, 60);
|
||||
Session session = newSession(fManager.getUserAuthenticator(this), subMon.newChild(10));
|
||||
if (!hasOpenSession()) {
|
||||
checkIsConfigured();
|
||||
newSession(fManager.getUserAuthenticator(this), subMon.newChild(10));
|
||||
if (subMon.isCanceled()) {
|
||||
throw new RemoteConnectionException(Messages.JSchConnection_Connection_was_cancelled);
|
||||
}
|
||||
isFullySetup = false;
|
||||
}
|
||||
if (setupFully && !isFullySetup) { // happens on the first open with setupFully==true, which might not be the first open
|
||||
isFullySetup = true;
|
||||
// getCwd checks the exec channel before checkConfiguration checks the sftp channel
|
||||
fWorkingDir = getCwd(subMon.newChild(10));
|
||||
if (!checkConfiguration(session, subMon.newChild(20))) {
|
||||
if (!checkConfiguration(fSessions.get(0), subMon.newChild(20))) {
|
||||
newSession(fManager.getUserAuthenticator(this), subMon.newChild(10));
|
||||
loadEnv(subMon.newChild(10));
|
||||
}
|
||||
|
|
|
@ -24,13 +24,15 @@ import org.eclipse.core.runtime.IProgressMonitor;
|
|||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.SubMonitor;
|
||||
import org.eclipse.remote.core.IRemoteConnection;
|
||||
import org.eclipse.remote.core.IRemoteConnectionManager;
|
||||
import org.eclipse.remote.core.IRemoteProcess;
|
||||
import org.eclipse.remote.core.IRemoteProcessBuilder;
|
||||
import org.eclipse.remote.core.RemoteServices;
|
||||
import org.eclipse.remote.core.exception.RemoteConnectionException;
|
||||
import org.eclipse.remote.internal.jsch.core.messages.Messages;
|
||||
|
||||
import com.jcraft.jsch.Channel;
|
||||
import com.jcraft.jsch.ChannelExec;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.Proxy;
|
||||
import com.jcraft.jsch.SocketFactory;
|
||||
|
||||
|
@ -45,11 +47,12 @@ public class JSchConnectionProxyFactory {
|
|||
private static class CommandProxy implements Proxy {
|
||||
private String command;
|
||||
private IRemoteProcess process;
|
||||
private IRemoteConnection connection;
|
||||
private JSchConnection connection;
|
||||
private IProgressMonitor monitor;
|
||||
private boolean connectCalled = false;
|
||||
|
||||
private CommandProxy(IRemoteConnection connection, String command, IProgressMonitor monitor) {
|
||||
if (command == null || connection == null || monitor == null)
|
||||
private CommandProxy(JSchConnection connection, String command, IProgressMonitor monitor) {
|
||||
if (command == null || monitor == null)
|
||||
throw new IllegalArgumentException();
|
||||
this.command = command;
|
||||
this.connection = connection;
|
||||
|
@ -74,33 +77,45 @@ public class JSchConnectionProxyFactory {
|
|||
@Override
|
||||
public void connect(SocketFactory socket_factory, String host,
|
||||
int port, int timeout) throws IOException {
|
||||
assert connection != null : "connect should only be called once"; //$NON-NLS-1$
|
||||
assert !connectCalled : "connect should only be called once"; //$NON-NLS-1$
|
||||
try {
|
||||
if (timeout == 0) {
|
||||
timeout = 10000; // default to 10s
|
||||
}
|
||||
final int waitTime = 50;
|
||||
final int waitSteps = timeout / waitTime;
|
||||
SubMonitor subMon;
|
||||
SubMonitor subMon = SubMonitor.convert(monitor, waitSteps * 2);
|
||||
final SubMonitor childMon = subMon.newChild(waitSteps);
|
||||
|
||||
// Open connection if it isn't already opened
|
||||
if (!connection.isOpen()) {
|
||||
subMon = SubMonitor.convert(monitor, waitSteps * 2);
|
||||
try {
|
||||
connection.open(subMon.newChild(waitSteps));
|
||||
} catch (RemoteConnectionException e) {
|
||||
throw new IOException(e);
|
||||
try {
|
||||
if (connection != null) {
|
||||
connection.openMinimal(childMon);
|
||||
}
|
||||
} else {
|
||||
subMon = SubMonitor.convert(monitor, waitSteps);
|
||||
} catch (RemoteConnectionException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
subMon.setWorkRemaining(waitSteps);
|
||||
|
||||
// Start command
|
||||
command = command.replace("%h", host); //$NON-NLS-1$
|
||||
command = command.replace("%p", Integer.toString(port)); //$NON-NLS-1$
|
||||
List<String> cmd = new ArgumentParser(command).getTokenList();
|
||||
IRemoteProcessBuilder pb = connection.getProcessBuilder(cmd);
|
||||
process = pb.start();
|
||||
|
||||
if (connection != null) {
|
||||
// The process-builder adds unnecessary extra commands (cd, export, ..) and might not work for restricted shells
|
||||
try {
|
||||
ChannelExec exec = connection.getExecChannel();
|
||||
exec.setCommand(command);
|
||||
exec.connect();
|
||||
process = new JSchProcess(exec, false);
|
||||
} catch (JSchException | RemoteConnectionException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
} else {
|
||||
List<String> cmd = new ArgumentParser(command).getTokenList();
|
||||
process = RemoteServices.getLocalServices().getConnectionManager().getConnection(
|
||||
IRemoteConnectionManager.LOCAL_CONNECTION_NAME).getProcessBuilder(cmd).start();
|
||||
}
|
||||
|
||||
// Wait on command to produce stdout output
|
||||
long endTime = System.currentTimeMillis() + timeout;
|
||||
|
@ -158,8 +173,7 @@ public class JSchConnectionProxyFactory {
|
|||
};
|
||||
}.start();
|
||||
} finally {
|
||||
// Not valid to call connect again or for any other command to access these variables. Setting to null to ensure.
|
||||
connection = null;
|
||||
connectCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,11 +212,12 @@ public class JSchConnectionProxyFactory {
|
|||
private Channel channel;
|
||||
private JSchConnection connection;
|
||||
private IProgressMonitor monitor;
|
||||
private boolean connectCalled = false;
|
||||
|
||||
private SSHForwardProxy(IRemoteConnection proxyConnection, IProgressMonitor monitor) {
|
||||
private SSHForwardProxy(JSchConnection proxyConnection, IProgressMonitor monitor) {
|
||||
if (proxyConnection == null || monitor == null)
|
||||
throw new IllegalArgumentException();
|
||||
this.connection = (JSchConnection) proxyConnection; // only JSch supported for ForwardProxy
|
||||
this.connection = proxyConnection;
|
||||
this.monitor = monitor;
|
||||
}
|
||||
|
||||
|
@ -224,19 +239,18 @@ public class JSchConnectionProxyFactory {
|
|||
@Override
|
||||
public void connect(SocketFactory socket_factory, String host, int port,
|
||||
int timeout) throws Exception {
|
||||
assert connection != null : "connect should only be called once"; //$NON-NLS-1$
|
||||
assert !connectCalled : "connect should only be called once"; //$NON-NLS-1$
|
||||
try {
|
||||
if (!connection.isOpen()) {
|
||||
if (!connection.hasOpenSession()) {
|
||||
try {
|
||||
connection.open(monitor);
|
||||
connection.openMinimal(monitor);
|
||||
} catch (RemoteConnectionException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
channel = connection.getStreamForwarder(host, port);
|
||||
} finally {
|
||||
// Not valid to call connect again or for any other command to access these variables. Setting to null to ensure.
|
||||
connection = null;
|
||||
connectCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -285,14 +299,14 @@ public class JSchConnectionProxyFactory {
|
|||
* Creates a (local or remote) command proxy.
|
||||
*
|
||||
* @param connection
|
||||
* Any (local or remote) connection. Cannot be null.
|
||||
* Either a valid connection or null for a local command
|
||||
* @param command
|
||||
* A valid proxy command. Cannot be null or empty.
|
||||
* @param monitor
|
||||
* A valid progress monitor. Cannot be null.
|
||||
* @return ssh proxy
|
||||
*/
|
||||
public static Proxy createCommandProxy(IRemoteConnection connection, String command, IProgressMonitor monitor) {
|
||||
public static Proxy createCommandProxy(JSchConnection connection, String command, IProgressMonitor monitor) {
|
||||
return new CommandProxy(connection, command, monitor);
|
||||
}
|
||||
|
||||
|
@ -305,7 +319,7 @@ public class JSchConnectionProxyFactory {
|
|||
* A valid progress monitor. Cannot be null.
|
||||
* @return ssh proxy
|
||||
*/
|
||||
public static Proxy createForwardProxy(IRemoteConnection proxyConnection, IProgressMonitor monitor) {
|
||||
public static Proxy createForwardProxy(JSchConnection proxyConnection, IProgressMonitor monitor) {
|
||||
return new SSHForwardProxy(proxyConnection, monitor);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue