1
0
Fork 0
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:
Roland Schulz 2014-10-02 20:27:22 -04:00 committed by John Eblen
parent b1903767f3
commit 95db103e5b
5 changed files with 106 additions and 57 deletions

View file

@ -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"/>

View file

@ -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

View file

@ -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

View file

@ -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));
}

View file

@ -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);
}
}