diff --git a/bundles/org.eclipse.remote.jsch.core/.classpath b/bundles/org.eclipse.remote.jsch.core/.classpath index ad32c83a788..098194ca4b7 100644 --- a/bundles/org.eclipse.remote.jsch.core/.classpath +++ b/bundles/org.eclipse.remote.jsch.core/.classpath @@ -1,6 +1,6 @@ - + diff --git a/bundles/org.eclipse.remote.jsch.core/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.remote.jsch.core/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..7341ab1683c 100644 --- a/bundles/org.eclipse.remote.jsch.core/.settings/org.eclipse.jdt.core.prefs +++ b/bundles/org.eclipse.remote.jsch.core/.settings/org.eclipse.jdt.core.prefs @@ -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 diff --git a/bundles/org.eclipse.remote.jsch.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.remote.jsch.core/META-INF/MANIFEST.MF index ea7ea982951..a004fb31789 100644 --- a/bundles/org.eclipse.remote.jsch.core/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.remote.jsch.core/META-INF/MANIFEST.MF @@ -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 diff --git a/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchConnection.java b/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchConnection.java index 151bd25c370..0ca81d6c5b3 100644 --- a/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchConnection.java +++ b/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchConnection.java @@ -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 fSessions = new ArrayList(); 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)); } diff --git a/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchConnectionProxyFactory.java b/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchConnectionProxyFactory.java index d0e33d43e78..dbd496cb4e1 100644 --- a/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchConnectionProxyFactory.java +++ b/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchConnectionProxyFactory.java @@ -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 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 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); } }