1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-02 22:55:26 +02:00

Bug 530750 - Enable launch support using proxy. Also adds support for

command shell and fixes a number of bugs.

Change-Id: I6b9a0bf40647d6f5682c425c754371f8af6cb918
Signed-off-by: Greg Watson <g.watson@computer.org>
This commit is contained in:
Greg Watson 2018-02-08 16:24:42 -05:00
parent a0fe3f1cf2
commit ea50b5d22c
45 changed files with 703 additions and 344 deletions

View file

@ -40,7 +40,7 @@
</connectionService>
<connectionService
connectionTypeId="org.eclipse.remote.Proxy"
factory="org.eclipse.remote.internal.proxy.core.ProxyCommandShellService$Factory"
factory="org.eclipse.remote.internal.proxy.core.ProxyConnection$Factory"
service="org.eclipse.remote.core.IRemoteCommandShellService">
</connectionService>
<processService
@ -58,6 +58,11 @@
factory="org.eclipse.remote.internal.proxy.core.ProxyProcess$Factory"
service="org.eclipse.remote.core.IRemoteProcessTerminalService">
</processService>
<processService
connectionTypeId="org.eclipse.remote.Proxy"
factory="org.eclipse.remote.internal.proxy.core.ProxyProcess$Factory"
service="org.eclipse.remote.internal.proxy.core.ProxyProcess">
</processService>
</extension>
<extension
id="org.eclipse.remote.proxy.filesystem"

View file

@ -1,53 +0,0 @@
/*******************************************************************************
* Copyright (c) 2015 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
package org.eclipse.remote.internal.proxy.core;
import java.io.IOException;
import org.eclipse.remote.core.IRemoteCommandShellService;
import org.eclipse.remote.core.IRemoteConnection;
import org.eclipse.remote.core.IRemoteProcess;
public class ProxyCommandShellService implements IRemoteCommandShellService {
private IRemoteConnection fRemoteConnection;
public ProxyCommandShellService(IRemoteConnection remoteConnection) {
fRemoteConnection = remoteConnection;
}
@Override
public IRemoteConnection getRemoteConnection() {
return fRemoteConnection;
}
@Override
public IRemoteProcess getCommandShell(int flags) throws IOException {
return null;
// return new JSchProcessBuilder(getRemoteConnection()).start(flags);
}
public static class Factory implements IRemoteConnection.Service.Factory {
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnection.Service.Factory#getService(org.eclipse.remote.core.IRemoteConnection,
* java.lang.Class)
*/
@Override
@SuppressWarnings("unchecked")
public <T extends IRemoteConnection.Service> T getService(IRemoteConnection connection, Class<T> service) {
if (IRemoteCommandShellService.class.equals(service)) {
return (T) new ProxyCommandShellService(connection);
}
return null;
}
}
}

View file

@ -37,8 +37,8 @@ import org.eclipse.remote.internal.proxy.core.commands.GetCwdCommand;
import org.eclipse.remote.internal.proxy.core.commands.GetEnvCommand;
import org.eclipse.remote.internal.proxy.core.commands.GetPropertiesCommand;
import org.eclipse.remote.internal.proxy.core.messages.Messages;
import org.eclipse.remote.proxy.protocol.core.StreamChannelManager;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
import org.eclipse.remote.proxy.protocol.core.StreamChannelManager;
import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException;
import com.jcraft.jsch.ChannelShell;
@ -48,7 +48,8 @@ import com.jcraft.jsch.ChannelShell;
*/
public class ProxyConnection implements IRemoteConnectionControlService,
IRemoteConnectionChangeListener, IRemoteProcessService,
IRemoteCommandShellService, IRemoteConnectionHostService {
IRemoteCommandShellService, IRemoteConnectionHostService,
IRemoteConnectionPropertyService {
// Connection Type ID
public static final String JSCH_ID = "org.eclipse.remote.Proxy"; //$NON-NLS-1$
@ -72,7 +73,6 @@ public class ProxyConnection implements IRemoteConnectionControlService,
private StreamChannelManager channelMux;
private StreamChannel commandChannel;
private boolean isOpen;
private boolean proxyRunning;
private final IRemoteConnection fRemoteConnection;
@ -133,7 +133,8 @@ public class ProxyConnection implements IRemoteConnectionControlService,
|| IRemoteConnectionPropertyService.class.equals(service)
|| IRemoteConnectionHostService.class.equals(service)
|| IRemoteProcessService.class.equals(service)
|| IRemoteCommandShellService.class.equals(service)) {
|| IRemoteCommandShellService.class.equals(service)
|| IRemoteConnectionPropertyService.class.equals(service)) {
return (T) connection.getService(ProxyConnection.class);
} else {
return null;
@ -348,7 +349,7 @@ public class ProxyConnection implements IRemoteConnectionControlService,
@Override
public IRemoteProcess getCommandShell(int flags) throws IOException {
throw new IOException("Not implemented yet");
return new ProxyProcessBuilder(this).start(flags);
}
@Override
@ -454,4 +455,9 @@ public class ProxyConnection implements IRemoteConnectionControlService,
wc.setAttribute(USERNAME_ATTR, username);
}
}
@Override
public String getProperty(String key) {
return fProperties.get(key);
}
}

View file

@ -211,7 +211,7 @@ public class ProxyConnectionBootstrap {
int n;
while ((n = in.read(buf)) >= 0) {
if (n < 510) {
writer.write(encoder.encodeToString(Arrays.copyOf(buf, n)) + "\n");
writer.write(encoder.encodeToString(Arrays.copyOf(buf, n)) + "\n"); //$NON-NLS-1$
} else {
writer.write(encoder.encodeToString(buf));
}
@ -311,7 +311,7 @@ public class ProxyConnectionBootstrap {
throw new RemoteConnectionException(Messages.ProxyConnectionBootstrap_8);
}
exec = (ChannelExec) session.openChannel("exec"); //$NON-NLS-1$
exec.setCommand("/bin/sh -l"); //$NON-NLS-1$
exec.setCommand("/bin/bash -l"); //$NON-NLS-1$
exec.connect();
return exec;
} catch (JSchException e) {

View file

@ -12,18 +12,18 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import org.eclipse.remote.core.IRemoteConnection;
import org.eclipse.remote.core.IRemoteProcess;
import org.eclipse.remote.core.IRemoteProcessBuilder;
import org.eclipse.remote.core.IRemoteProcessControlService;
import org.eclipse.remote.core.IRemoteProcessSignalService;
import org.eclipse.remote.core.IRemoteProcessTerminalService;
import org.eclipse.remote.internal.core.RemoteProcess;
import org.eclipse.remote.proxy.protocol.core.Protocol;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
public class ProxyProcess extends RemoteProcess implements IRemoteProcessControlService, IRemoteProcessTerminalService {
public class ProxyProcess implements IRemoteProcessControlService, IRemoteProcessTerminalService {
private IRemoteProcess remoteProcess;
private final StreamChannel stdIOChan;
private final StreamChannel stdErrChan;
private final StreamChannel controlChan;
@ -44,8 +44,8 @@ public class ProxyProcess extends RemoteProcess implements IRemoteProcessControl
@SuppressWarnings("unchecked")
@Override
public <T extends IRemoteProcess.Service> T getService(IRemoteProcess remoteProcess, Class<T> service) {
if (ProxyProcess.class.equals(service) && remoteProcess instanceof ProxyProcess) {
return (T) remoteProcess;
if (ProxyProcess.class.equals(service)) {
return (T) new ProxyProcess(remoteProcess);
}
if (IRemoteProcessControlService.class.equals(service) || IRemoteProcessSignalService.class.equals(service)
|| IRemoteProcessTerminalService.class.equals(service)) {
@ -55,17 +55,19 @@ public class ProxyProcess extends RemoteProcess implements IRemoteProcessControl
}
}
public ProxyProcess(IRemoteConnection connection, IRemoteProcessBuilder builder, StreamChannel stdIO, StreamChannel stdErr, StreamChannel control) {
super(connection, builder);
stdIOChan = stdIO;
stdErrChan = stdErr;
controlChan = control;
cmdStream = new DataOutputStream(control.getOutputStream());
resultStream = new DataInputStream(control.getInputStream());
protected ProxyProcess(IRemoteProcess process) {
remoteProcess = process;
ProxyProcessBuilder builder = (ProxyProcessBuilder)process.getProcessBuilder();
List<StreamChannel> streams = builder.getStreams();
controlChan = streams.get(0);
stdIOChan = streams.get(1);
stdErrChan = streams.size() > 2 ? streams.get(2) : null;
cmdStream = new DataOutputStream(controlChan.getOutputStream());
resultStream = new DataInputStream(controlChan.getInputStream());
isCompleted = false;
exitValue = 0;
cmdThread = new Thread("process " + builder.command().get(0) + " result reader") { //$NON-NLS-1$ //$NON-NLS-2$
cmdThread = new Thread("process result reader") { //$NON-NLS-1$
@Override
public void run() {
try {
@ -77,36 +79,15 @@ public class ProxyProcess extends RemoteProcess implements IRemoteProcessControl
try {
stdIOChan.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
// Ignore
}
try {
stdErrChan.close();
if (stdErrChan != null) {
stdErrChan.close();
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
// Ignore
}
// if (stdout == null) {
// try {
// stdIOChan.getInputStream().close();
// } catch (IOException e) {
// // Ignore
// }
// }
// if (stdin == null) {
// try {
// stdIOChan.getOutputStream().close();
// } catch (IOException e) {
// // Ignore
// }
// }
// if (stderr == null) {
// try {
// stdErrChan.close();
// } catch (IOException e) {
// // Ignore
// }
// }
try {
controlChan.close();
} catch (IOException e) {
@ -125,7 +106,7 @@ public class ProxyProcess extends RemoteProcess implements IRemoteProcessControl
@Override
public void destroy() {
try {
cmdStream.writeByte(0);
cmdStream.writeByte(Protocol.CONTROL_KILL);
cmdStream.flush();
} catch (IOException e) {
isCompleted = true;
@ -152,6 +133,19 @@ public class ProxyProcess extends RemoteProcess implements IRemoteProcessControl
*/
@Override
public InputStream getErrorStream() {
if (stdErrChan == null) {
return new InputStream() {
@Override
public int read() throws IOException {
return -1;
}
@Override
public int available() {
return 0;
}
};
}
return stdErrChan.getInputStream();
}
@ -203,6 +197,15 @@ public class ProxyProcess extends RemoteProcess implements IRemoteProcessControl
@Override
public void setTerminalSize(int cols, int rows, int pwidth, int pheight) {
// Nothing?
try {
cmdStream.writeByte(Protocol.CONTROL_SETTERMINALSIZE);
cmdStream.writeInt(cols);
cmdStream.writeInt(rows);
cmdStream.writeInt(pwidth);
cmdStream.writeInt(pheight);
cmdStream.flush();
} catch (IOException e) {
// Dealt with somewhere else hopefully
}
}
}

View file

@ -8,6 +8,7 @@
package org.eclipse.remote.internal.proxy.core;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@ -22,6 +23,7 @@ import org.eclipse.remote.core.IRemoteFileService;
import org.eclipse.remote.core.IRemoteProcess;
import org.eclipse.remote.core.IRemoteProcessBuilder;
import org.eclipse.remote.internal.proxy.core.commands.ExecCommand;
import org.eclipse.remote.internal.proxy.core.commands.ShellCommand;
import org.eclipse.remote.internal.proxy.core.messages.Messages;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException;
@ -29,6 +31,7 @@ import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException;
public class ProxyProcessBuilder extends AbstractRemoteProcessBuilder {
private final ProxyConnection proxyConnection;
private Map<String, String> remoteEnv;
private List<StreamChannel> streams = new ArrayList<>();
public ProxyProcessBuilder(ProxyConnection connection, List<String> command) {
super(connection.getRemoteConnection(), command);
@ -42,6 +45,17 @@ public class ProxyProcessBuilder extends AbstractRemoteProcessBuilder {
public ProxyProcessBuilder(ProxyConnection connection, String... command) {
this(connection, Arrays.asList(command));
}
/**
* Constructor for creating command shell
* @param connection
*/
public ProxyProcessBuilder(ProxyConnection connection) {
super(connection.getRemoteConnection(), (List<String>)null);
proxyConnection = connection;
redirectErrorStream(true);
}
/*
* (non-Javadoc)
@ -76,41 +90,66 @@ public class ProxyProcessBuilder extends AbstractRemoteProcessBuilder {
*/
@Override
public IRemoteProcess start(int flags) throws IOException {
final List<String> cmdArgs = command();
if (cmdArgs.size() < 1) {
throw new IndexOutOfBoundsException();
}
/*
* If environment has not been touched, then don't send anything
*/
final Map<String, String> env = new HashMap<String, String>();
if (remoteEnv != null) {
env.putAll(remoteEnv);
}
final boolean append = (flags & IRemoteProcessBuilder.APPEND_ENVIRONMENT) != 0 || remoteEnv == null;
final ProxyConnection conn = getRemoteConnection().getService(ProxyConnection.class);
if (conn == null) {
throw new IOException(Messages.ProxyProcessBuilder_0);
}
final StreamChannel chanStdIO = conn.openChannel();
final StreamChannel chanStdErr = conn.openChannel();
final StreamChannel chanControl = conn.openChannel();
Job job;
Job job = new Job("process executor") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
ExecCommand cmd = new ExecCommand(conn, cmdArgs, env, directory().toURI().getPath(), redirectErrorStream(), append,
chanStdIO.getId(), chanStdErr.getId(), chanControl.getId());
try {
cmd.getResult(monitor);
} catch (ProxyException e) {
return new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage());
}
return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS;
final List<String> cmdArgs = command();
if (cmdArgs != null) {
if (cmdArgs.size() < 1) {
throw new IOException(Messages.ProxyProcessBuilder_1);
}
};
/*
* If environment has not been touched, then don't send anything
*/
final Map<String, String> env = new HashMap<String, String>();
if (remoteEnv != null) {
env.putAll(remoteEnv);
}
final boolean append = (flags & IRemoteProcessBuilder.APPEND_ENVIRONMENT) != 0 || remoteEnv == null;
streams.add(conn.openChannel());
streams.add(conn.openChannel());
streams.add(conn.openChannel());
job = new Job("process executor") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
ExecCommand cmd = new ExecCommand(conn, cmdArgs, env, directory().toURI().getPath(), redirectErrorStream(), append,
streams.get(0).getId(), streams.get(1).getId(), streams.get(2).getId());
try {
cmd.getResult(monitor);
} catch (ProxyException e) {
return new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage());
}
return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS;
}
};
} else {
/*
* Start command shell
*/
streams.add(conn.openChannel());
streams.add(conn.openChannel());
job = new Job("process executor") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
ShellCommand cmd = new ShellCommand(conn, streams.get(0).getId(), streams.get(1).getId());
try {
cmd.getResult(monitor);
} catch (ProxyException e) {
return new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage());
}
return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS;
}
};
}
job.schedule();
try {
job.join();
@ -121,7 +160,10 @@ public class ProxyProcessBuilder extends AbstractRemoteProcessBuilder {
throw new IOException(job.getResult().getMessage());
}
ProxyProcess proc = new ProxyProcess(getRemoteConnection(), this, chanStdIO, chanStdErr, chanControl);
return proc;
return newRemoteProcess();
}
public List<StreamChannel> getStreams() {
return streams;
}
}

View file

@ -19,6 +19,7 @@ import java.util.concurrent.TimeoutException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.remote.internal.proxy.core.ProxyConnection;
import org.eclipse.remote.internal.proxy.core.messages.Messages;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException;
@ -28,15 +29,11 @@ public abstract class AbstractCommand<T> implements Callable<T> {
private static ExecutorService executors = Executors.newSingleThreadExecutor();
private final ProxyConnection connection;
private Future<T> asyncCmdInThread() throws ProxyException {
return executors.submit(this);
}
private void finalizeCmdInThread() {
}
public StreamChannel openChannel() throws IOException {
return connection.openChannel();
}
@ -52,12 +49,8 @@ public abstract class AbstractCommand<T> implements Callable<T> {
public T getResult(IProgressMonitor monitor) throws ProxyException {
Future<T> future = null;
progressMonitor = SubMonitor.convert(monitor, 10);
try {
future = asyncCmdInThread();
return waitCmdInThread(future);
} finally {
finalizeCmdInThread();
}
future = asyncCmdInThread();
return waitCmdInThread(future);
}
private T waitCmdInThread(Future<T> future) throws ProxyException {
@ -78,7 +71,7 @@ public abstract class AbstractCommand<T> implements Callable<T> {
Thread.currentThread().interrupt(); // set current thread flag
}
future.cancel(true);
throw new ProxyException("Operation cancelled by user");
throw new ProxyException(Messages.AbstractCommand_0);
}
@Override

View file

@ -44,7 +44,6 @@ public class ChildInfosCommand extends AbstractCommand<IFileInfo[]> {
byte res = in.readByte();
if (res != Protocol.PROTO_OK) {
String errMsg = in.readUTF();
System.err.println("childinfos command failed:" + errMsg);
throw new ProxyException(errMsg);
}

View file

@ -41,7 +41,6 @@ public class DeleteCommand extends AbstractCommand<Void> {
byte res = in.readByte();
if (res != Protocol.PROTO_OK) {
String errMsg = in.readUTF();
System.err.println("delete command failed:" + errMsg);
throw new ProxyException(errMsg);
}
return null;

View file

@ -26,12 +26,12 @@ public class ExecCommand extends AbstractCommand<Void> {
private final String directory;
private final boolean appendEnv;
private final boolean redirect;
private final int chanA;
private final int chanB;
private final int chanC;
private final int cmdChan;
private final int ioChan;
private final int errChan;
public ExecCommand(ProxyConnection conn, List<String> command, Map<String, String> env, String directory, boolean redirect, boolean appendEnv,
int chanA, int chanB, int chanC) {
int cmdChan, int ioChan, int errChan) {
super(conn);
this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream());
this.in = new DataInputStream(conn.getCommandChannel().getInputStream());
@ -40,18 +40,18 @@ public class ExecCommand extends AbstractCommand<Void> {
this.directory = directory;
this.redirect = redirect;
this.appendEnv = appendEnv;
this.chanA = chanA;
this.chanB = chanB;
this.chanC = chanC;
this.cmdChan = cmdChan;
this.ioChan = ioChan;
this.errChan = errChan;
}
public Void call() throws ProxyException {
try {
out.writeByte(Protocol.PROTO_COMMAND);
out.writeShort(Protocol.CMD_EXEC);
out.writeByte(chanA);
out.writeByte(chanB);
out.writeByte(chanC);
out.writeByte(cmdChan);
out.writeByte(ioChan);
out.writeByte(errChan);
out.writeInt(command.size());
for (String arg : command) {
out.writeUTF(arg);
@ -69,7 +69,6 @@ public class ExecCommand extends AbstractCommand<Void> {
byte res = in.readByte();
if (res != Protocol.PROTO_OK) {
String errMsg = in.readUTF();
System.err.println("exec command failed:" + errMsg);
throw new ProxyException(errMsg);
}
} catch (IOException e) {

View file

@ -44,7 +44,6 @@ public class FetchInfoCommand extends AbstractCommand<IFileInfo> {
byte res = in.readByte();
if (res != Protocol.PROTO_OK) {
String errMsg = in.readUTF();
System.err.println("fetchinfo command failed:" + errMsg);
throw new ProxyException(errMsg);
}

View file

@ -40,7 +40,6 @@ public class GetCwdCommand extends AbstractCommand<String> {
byte res = in.readByte();
if (res != Protocol.PROTO_OK) {
String errMsg = in.readUTF();
System.err.println("getcwd command failed:" + errMsg);
throw new ProxyException(errMsg);
}

View file

@ -42,7 +42,6 @@ public class GetEnvCommand extends AbstractCommand<Map<String, String>> {
byte res = in.readByte();
if (res != Protocol.PROTO_OK) {
String errMsg = in.readUTF();
System.err.println("getenv command failed:" + errMsg);
throw new ProxyException(errMsg);
}

View file

@ -14,8 +14,8 @@ import java.io.IOException;
import java.io.InputStream;
import org.eclipse.remote.internal.proxy.core.ProxyConnection;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
import org.eclipse.remote.proxy.protocol.core.Protocol;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException;
public class GetInputStreamCommand extends AbstractCommand<InputStream> {
@ -47,7 +47,6 @@ public class GetInputStreamCommand extends AbstractCommand<InputStream> {
byte res = in.readByte();
if (res != Protocol.PROTO_OK) {
String errMsg = in.readUTF();
System.err.println("getinputstream command failed:" + errMsg);
throw new ProxyException(errMsg);
}

View file

@ -14,8 +14,8 @@ import java.io.IOException;
import java.io.OutputStream;
import org.eclipse.remote.internal.proxy.core.ProxyConnection;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
import org.eclipse.remote.proxy.protocol.core.Protocol;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException;
public class GetOutputStreamCommand extends AbstractCommand<OutputStream> {
@ -47,7 +47,6 @@ public class GetOutputStreamCommand extends AbstractCommand<OutputStream> {
byte res = in.readByte();
if (res != Protocol.PROTO_OK) {
String errMsg = in.readUTF();
System.err.println("getoutputstream command failed:" + errMsg);
throw new ProxyException(errMsg);
}

View file

@ -42,7 +42,6 @@ public class GetPropertiesCommand extends AbstractCommand<Map<String, String>> {
byte res = in.readByte();
if (res != Protocol.PROTO_OK) {
String errMsg = in.readUTF();
System.err.println("getproperties command failed:" + errMsg);
throw new ProxyException(errMsg);
}

View file

@ -41,7 +41,6 @@ public class MkdirCommand extends AbstractCommand<Void> {
byte res = in.readByte();
if (res != Protocol.PROTO_OK) {
String errMsg = in.readUTF();
System.err.println("mkdir command failed:" + errMsg);
throw new ProxyException(errMsg);
}
return null;

View file

@ -47,7 +47,6 @@ public class PutInfoCommand extends AbstractCommand<Void> {
byte res = in.readByte();
if (res != Protocol.PROTO_OK) {
String errMsg = in.readUTF();
System.err.println("fetchinfo command failed:" + errMsg);
throw new ProxyException(errMsg);
}
return null;

View file

@ -0,0 +1,51 @@
/*******************************************************************************
* Copyright (c) 2016 Oak Ridge National Laboratory and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.core.commands;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.eclipse.remote.internal.proxy.core.ProxyConnection;
import org.eclipse.remote.proxy.protocol.core.Protocol;
import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException;
public class ShellCommand extends AbstractCommand<Void> {
private final DataOutputStream out;
private final DataInputStream in;
private final int cmdChan;
private final int ioChan;
public ShellCommand(ProxyConnection conn, int cmdChan, int ioChan) {
super(conn);
this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream());
this.in = new DataInputStream(conn.getCommandChannel().getInputStream());
this.cmdChan = cmdChan;
this.ioChan = ioChan;
}
public Void call() throws ProxyException {
try {
out.writeByte(Protocol.PROTO_COMMAND);
out.writeShort(Protocol.CMD_SHELL);
out.writeByte(cmdChan);
out.writeByte(ioChan);
out.flush();
byte res = in.readByte();
if (res != Protocol.PROTO_OK) {
String errMsg = in.readUTF();
throw new ProxyException(errMsg);
}
} catch (IOException e) {
throw new ProxyException(e.getMessage());
}
return null;
}
}

View file

@ -16,6 +16,8 @@ import org.eclipse.osgi.util.NLS;
public class Messages extends NLS {
private static final String BUNDLE_ID = "org.eclipse.remote.internal.proxy.core.messages.messages"; //$NON-NLS-1$
public static String AbstractCommand_0;
public static String AbstractRemoteCommand_format1;
public static String AbstractRemoteCommand_format2;
public static String AbstractRemoteCommand_Get_symlink_target;
@ -56,6 +58,8 @@ public class Messages extends NLS {
public static String JschFileStore_A_file_of_name_already_exists;
public static String JschFileStore_The_parent_of_directory_does_not_exist;
public static String ProxyCommandShell_0;
public static String ProxyConnection_0;
public static String ProxyConnection_2;
@ -98,6 +102,8 @@ public class Messages extends NLS {
public static String ProxyProcessBuilder_0;
public static String ProxyProcessBuilder_1;
static {
// load message values from bundle file
NLS.initializeMessages(BUNDLE_ID, Messages.class);

View file

@ -8,6 +8,7 @@
# Contributors:
# IBM Corporation - initial implementation
###############################################################################
AbstractCommand_0=Operation cancelled by user
AbstractRemoteCommand_format1={0,number,integer} {1} completed
AbstractRemoteCommand_format2={0,number,integer} {1} of {2,number,integer} {3} complete ({4,number,percent})
AbstractRemoteCommand_Get_symlink_target=Get symlink target
@ -43,6 +44,7 @@ JschFileStore_No_remote_services_found_for_URI=No remote services found for URI:
JschFileStore_The_directory_could_not_be_created=The directory {0} could not be created
JschFileStore_A_file_of_name_already_exists=A file of name {0} already exists
JschFileStore_The_parent_of_directory_does_not_exist=The parent of directory {0} does not exist
ProxyCommandShell_0=Unable to locate connection for command shell
ProxyConnection_0=Opening connection...
ProxyConnection_2=User canceled opening connection
ProxyConnectionBootstrap_0=Initializing
@ -64,3 +66,4 @@ ProxyFileStore_5=A file of name {0} already exists
ProxyFileStore_6=File {0} does not exist
ProxyFileStore_7={0} is a directory
ProxyProcessBuilder_0=Unable to located connection for this process
ProxyProcessBuilder_1=No command to run\!

View file

@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.remote.proxy.protocol.core;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Version: 2.0.0.qualifier
Bundle-Activator: org.eclipse.remote.internal.proxy.protocol.core.Activator
Bundle-Vendor: %pluginProvider
Bundle-ActivationPolicy: lazy

View file

@ -12,5 +12,5 @@
<artifactId>org.eclipse.remote.proxy.protocol.core</artifactId>
<packaging>eclipse-plugin</packaging>
<version>1.0.0-SNAPSHOT</version>
<version>2.0.0-SNAPSHOT</version>
</project>

View file

@ -17,16 +17,25 @@ public class Protocol {
public final static short CmdBase = 100;
public final static short CMD_EXEC = CmdBase + 1;
public final static short CMD_SHELL = CmdBase + 2;
public final static short CMD_GETCWD = CmdBase + 3;
public final static short CMD_GETENV = CmdBase + 4;
public final static short CMD_CHILDINFOS = CmdBase + 5;
public final static short CMD_DELETE = CmdBase + 6;
public final static short CMD_FETCHINFO = CmdBase + 7;
public final static short CMD_GETINPUTSTREAM = CmdBase + 8;
public final static short CMD_EXEC = CmdBase + 1;
public final static short CMD_SHELL = CmdBase + 2;
public final static short CMD_GETCWD = CmdBase + 3;
public final static short CMD_GETENV = CmdBase + 4;
public final static short CMD_CHILDINFOS = CmdBase + 5;
public final static short CMD_DELETE = CmdBase + 6;
public final static short CMD_FETCHINFO = CmdBase + 7;
public final static short CMD_GETINPUTSTREAM = CmdBase + 8;
public final static short CMD_GETOUTPUTSTREAM = CmdBase + 9;
public final static short CMD_MKDIR = CmdBase + 10;
public final static short CMD_MKDIR = CmdBase + 10;
public final static short CMD_PUTINFO = CmdBase + 11;
public final static short CMD_GETPROPERTIES = CmdBase + 12;
public final static short CMD_GETPROPERTIES = CmdBase + 12;
/**
* @since 2.0
*/
public final static byte CONTROL_KILL = 0;
/**
* @since 2.0
*/
public final static byte CONTROL_SETTERMINALSIZE = 1;
}

View file

@ -1,7 +1,12 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
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.8

View file

@ -0,0 +1,59 @@
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
sp_cleanup.add_default_serial_version_id=true
sp_cleanup.add_generated_serial_version_id=false
sp_cleanup.add_missing_annotations=true
sp_cleanup.add_missing_deprecated_annotations=true
sp_cleanup.add_missing_methods=false
sp_cleanup.add_missing_nls_tags=false
sp_cleanup.add_missing_override_annotations=true
sp_cleanup.add_missing_override_annotations_interface_methods=true
sp_cleanup.add_serial_version_id=false
sp_cleanup.always_use_blocks=true
sp_cleanup.always_use_parentheses_in_expressions=false
sp_cleanup.always_use_this_for_non_static_field_access=false
sp_cleanup.always_use_this_for_non_static_method_access=false
sp_cleanup.convert_functional_interfaces=false
sp_cleanup.convert_to_enhanced_for_loop=false
sp_cleanup.correct_indentation=false
sp_cleanup.format_source_code=false
sp_cleanup.format_source_code_changes_only=false
sp_cleanup.insert_inferred_type_arguments=false
sp_cleanup.make_local_variable_final=true
sp_cleanup.make_parameters_final=false
sp_cleanup.make_private_fields_final=true
sp_cleanup.make_type_abstract_if_missing_method=false
sp_cleanup.make_variable_declarations_final=false
sp_cleanup.never_use_blocks=false
sp_cleanup.never_use_parentheses_in_expressions=true
sp_cleanup.on_save_use_additional_actions=false
sp_cleanup.organize_imports=true
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
sp_cleanup.remove_private_constructors=true
sp_cleanup.remove_redundant_type_arguments=false
sp_cleanup.remove_trailing_whitespaces=false
sp_cleanup.remove_trailing_whitespaces_all=true
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
sp_cleanup.remove_unnecessary_casts=true
sp_cleanup.remove_unnecessary_nls_tags=false
sp_cleanup.remove_unused_imports=false
sp_cleanup.remove_unused_local_variables=false
sp_cleanup.remove_unused_private_fields=true
sp_cleanup.remove_unused_private_members=false
sp_cleanup.remove_unused_private_methods=true
sp_cleanup.remove_unused_private_types=true
sp_cleanup.sort_members=false
sp_cleanup.sort_members_all=false
sp_cleanup.use_anonymous_class_creation=false
sp_cleanup.use_blocks=false
sp_cleanup.use_blocks_only_for_return_and_throw=false
sp_cleanup.use_lambda=true
sp_cleanup.use_parentheses_in_expressions=false
sp_cleanup.use_this_for_non_static_field_access=false
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
sp_cleanup.use_this_for_non_static_method_access=false
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true

View file

@ -15,3 +15,4 @@ Import-Package: org.eclipse.core.filesystem,
org.osgi.framework.launch
Bundle-Vendor: %pluginProvider
Bundle-Localization: plugin
Require-Bundle: org.eclipse.cdt.core.native

View file

@ -25,7 +25,7 @@ public class Application implements IApplication {
public Object start(IApplicationContext context) throws Exception {
String[] args = (String[])context.getArguments().get(IApplicationContext.APPLICATION_ARGS);
for (String arg : args) {
if (arg.equals("-magic")) {
if (arg.equals("-magic")) { //$NON-NLS-1$
ByteBuffer b = ByteBuffer.allocate(4);
b.putInt(Protocol.MAGIC);
System.out.write(b.array());
@ -40,5 +40,6 @@ public class Application implements IApplication {
* @see org.eclipse.equinox.app.IApplication#stop()
*/
public void stop() {
// Nothing
}
}

View file

@ -16,18 +16,19 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.remote.internal.proxy.server.commands.AbstractServerCommand;
import org.eclipse.remote.internal.proxy.server.commands.ServerChildInfosCommand;
import org.eclipse.remote.internal.proxy.server.commands.ServerDeleteCommand;
import org.eclipse.remote.internal.proxy.server.commands.ServerExecCommand;
import org.eclipse.remote.internal.proxy.server.commands.ServerFetchInfoCommand;
import org.eclipse.remote.internal.proxy.server.commands.ServerGetCwdCommand;
import org.eclipse.remote.internal.proxy.server.commands.ServerGetEnvCommand;
import org.eclipse.remote.internal.proxy.server.commands.ServerGetInputStreamCommand;
import org.eclipse.remote.internal.proxy.server.commands.ServerGetOutputStreamCommand;
import org.eclipse.remote.internal.proxy.server.commands.ServerGetPropertiesCommand;
import org.eclipse.remote.internal.proxy.server.commands.ServerMkdirCommand;
import org.eclipse.remote.internal.proxy.server.commands.ServerPutInfoCommand;
import org.eclipse.remote.internal.proxy.server.core.commands.AbstractServerCommand;
import org.eclipse.remote.internal.proxy.server.core.commands.ServerChildInfosCommand;
import org.eclipse.remote.internal.proxy.server.core.commands.ServerDeleteCommand;
import org.eclipse.remote.internal.proxy.server.core.commands.ServerExecCommand;
import org.eclipse.remote.internal.proxy.server.core.commands.ServerFetchInfoCommand;
import org.eclipse.remote.internal.proxy.server.core.commands.ServerGetCwdCommand;
import org.eclipse.remote.internal.proxy.server.core.commands.ServerGetEnvCommand;
import org.eclipse.remote.internal.proxy.server.core.commands.ServerGetInputStreamCommand;
import org.eclipse.remote.internal.proxy.server.core.commands.ServerGetOutputStreamCommand;
import org.eclipse.remote.internal.proxy.server.core.commands.ServerGetPropertiesCommand;
import org.eclipse.remote.internal.proxy.server.core.commands.ServerMkdirCommand;
import org.eclipse.remote.internal.proxy.server.core.commands.ServerPutInfoCommand;
import org.eclipse.remote.internal.proxy.server.core.commands.ServerShellCommand;
import org.eclipse.remote.proxy.protocol.core.Protocol;
import org.eclipse.remote.proxy.protocol.core.SerializableFileInfo;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
@ -48,7 +49,7 @@ public class CommandServer implements Runnable {
}
public void run() {
new Thread("cmd reader") {
new Thread("cmd reader") { //$NON-NLS-1$
@Override
public void run() {
try {
@ -117,6 +118,10 @@ public class CommandServer implements Runnable {
serverCmd = cmdExec(in);
break;
case Protocol.CMD_SHELL:
serverCmd = cmdShell(in);
break;
case Protocol.CMD_FETCHINFO:
serverCmd = cmdFetchInfo(in);
break;
@ -151,16 +156,16 @@ public class CommandServer implements Runnable {
default:
System.err.println("Invalid command ID: " + cmd);
throw new ProxyException("Invalid command ID: " + cmd);
throw new ProxyException("Invalid command ID: " + cmd); //$NON-NLS-1$
}
serverCmd.exec();
}
private AbstractServerCommand cmdExec(DataInputStream in) throws ProxyException, IOException {
int chanAId = in.readByte();
int chanBId = in.readByte();
int chanCId = in.readByte();
int cmdChanId = in.readByte();
int ioChanId = in.readByte();
int errChanId = in.readByte();
int length = in.readInt();
List<String> command = new ArrayList<String>(length);
for (int i = 0; i < length; i++) {
@ -176,25 +181,30 @@ public class CommandServer implements Runnable {
String dir = in.readUTF();
boolean redirect = in.readBoolean();
boolean appendEnv = in.readBoolean();
System.err.print("dispatch: ");
for (String s:command) {
System.err.print(" " + s);
StreamChannel cmdChan = server.getChannel(cmdChanId);
StreamChannel ioChan = server.getChannel(ioChanId);
StreamChannel errChan= server.getChannel(errChanId);
if (cmdChan == null || ioChan == null || errChan == null) {
throw new ProxyException("Unable to locate channels for command"); //$NON-NLS-1$
}
System.err.println(" [" + chanAId + "," + chanBId+ ","+ chanCId + "]");
StreamChannel chanA = server.getChannel(chanAId);
StreamChannel chanB = server.getChannel(chanBId);
StreamChannel chanC= server.getChannel(chanCId);
if (chanA == null || chanB == null || chanC == null) {
throw new ProxyException("Unable to locate channels for command");
}
return new ServerExecCommand(command, env, dir, redirect, appendEnv, chanA, chanB, chanC);
return new ServerExecCommand(command, env, dir, redirect, appendEnv, cmdChan, ioChan, errChan);
}
private AbstractServerCommand cmdShell(DataInputStream in) throws ProxyException, IOException {
int cmdChanId = in.readByte();
int ioChanId = in.readByte();
StreamChannel cmdChan = server.getChannel(cmdChanId);
StreamChannel ioChan = server.getChannel(ioChanId);
if (cmdChan == null || ioChan == null) {
throw new ProxyException("Unable to locate channels for command"); //$NON-NLS-1$
}
return new ServerShellCommand(cmdChan, ioChan);
}
private AbstractServerCommand cmdGetCwd(DataInputStream in) throws ProxyException, IOException {
int chanId = in.readByte();
StreamChannel chan = server.getChannel(chanId);
if (chan == null) {
throw new ProxyException("Unable to locate channel for command");
throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$
}
return new ServerGetCwdCommand(chan);
}
@ -203,7 +213,7 @@ public class CommandServer implements Runnable {
int chanId = in.readByte();
StreamChannel chan = server.getChannel(chanId);
if (chan == null) {
throw new ProxyException("Unable to locate channel for command");
throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$
}
return new ServerGetEnvCommand(chan);
}
@ -212,7 +222,7 @@ public class CommandServer implements Runnable {
int chanId = in.readByte();
StreamChannel chan = server.getChannel(chanId);
if (chan == null) {
throw new ProxyException("Unable to locate channel for command");
throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$
}
return new ServerGetPropertiesCommand(chan);
}
@ -221,7 +231,7 @@ public class CommandServer implements Runnable {
int chanId = in.readByte();
StreamChannel chan = server.getChannel(chanId);
if (chan == null) {
throw new ProxyException("Unable to locate channel for command");
throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$
}
String path = in.readUTF();
return new ServerChildInfosCommand(chan, path);
@ -231,7 +241,7 @@ public class CommandServer implements Runnable {
int chanId = in.readByte();
StreamChannel chan = server.getChannel(chanId);
if (chan == null) {
throw new ProxyException("Unable to locate channel for command");
throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$
}
String path = in.readUTF();
return new ServerFetchInfoCommand(chan, path);
@ -241,7 +251,7 @@ public class CommandServer implements Runnable {
int chanId = in.readByte();
StreamChannel chan = server.getChannel(chanId);
if (chan == null) {
throw new ProxyException("Unable to locate channel for command");
throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$
}
int options = in.readInt();
String path = in.readUTF();
@ -252,7 +262,7 @@ public class CommandServer implements Runnable {
int chanId = in.readByte();
StreamChannel chan = server.getChannel(chanId);
if (chan == null) {
throw new ProxyException("Unable to locate channel for command");
throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$
}
int options = in.readInt();
String path = in.readUTF();

View file

@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.commands;
package org.eclipse.remote.internal.proxy.server.core.commands;
import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException;

View file

@ -5,14 +5,13 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.commands;
package org.eclipse.remote.internal.proxy.server.core.commands;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -23,83 +22,37 @@ import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.eclipse.remote.proxy.protocol.core.Protocol;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException;
/**
* TODO: Fix hang if command fails...
*
*/
public class ServerExecCommand extends AbstractServerCommand {
private final List<String> command;
private final Map<String, String> env;
private final boolean redirect;
private final boolean appendEnv;
private final String directory;
private final InputStream stdin;
private final OutputStream stdout;
private final OutputStream stderr;
private final DataOutputStream result;
private final DataInputStream cmd;
private Process proc;
public abstract class AbstractServerExecCommand extends AbstractServerCommand {
private class CommandRunner implements Runnable {
@Override
public void run() {
ProcessBuilder builder = new ProcessBuilder(command);
try {
if (!appendEnv) {
builder.environment().clear();
builder.environment().putAll(env);
} else {
for (Map.Entry<String, String> entry : env.entrySet()) {
String val = builder.environment().get(entry.getKey());
if (val == null || !val.equals(entry.getValue())) {
builder.environment().put(entry.getKey(), entry.getValue());
}
}
}
} catch (UnsupportedOperationException | IllegalArgumentException e) {
// Leave environment untouched
}
File dir = new File(directory);
if (dir.exists() && dir.isAbsolute()) {
builder.directory(dir);
}
builder.redirectErrorStream(redirect);
try {
int exit = 0;
try {
proc = builder.start();
Forwarder stdoutFwd = startForwarder("stdout", proc.getInputStream(), stdout); //$NON-NLS-1$
proc = doRun();
Forwarder stdoutFwd = startForwarder("stdout", proc.getInputStream(), stdoutChan); //$NON-NLS-1$
Forwarder stderrFwd = null;
if (!redirect) {
stderrFwd = startForwarder("stderr", proc.getErrorStream(), stderr); //$NON-NLS-1$
stderrFwd = startForwarder("stderr", proc.getErrorStream(), stderrChan); //$NON-NLS-1$
}
startForwarder("stdin", stdin, proc.getOutputStream()); //$NON-NLS-1$
startForwarder("stdin", stdinChan, proc.getOutputStream()); //$NON-NLS-1$
new Thread(new ProcMonitor(), "process monitor").start(); //$NON-NLS-1$
System.err.println("wait for process");
exit = proc.waitFor();
System.err.println("wait for process close in");
// stdoutFwd.terminate();
// if (!redirect) {
// stderrFwd.terminate();
// }
System.err.println("wait for readers");
/*
* After the process has finished, wait for the stdout and stderr forwarders to finish to
* ensure that all output is flushed.
*/
// stdoutFwd.waitFor();
// System.err.println("wait for process finished out");
// if (stderrFwd != null) {
// stderrFwd.waitFor();
// }
System.err.println("wait for readers done");
stdoutFwd.waitFor();
if (stderrFwd != null) {
stderrFwd.waitFor();
}
} catch (IOException e) {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stderr));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stderrChan));
try {
writer.write(e.getMessage());
writer.flush();
@ -109,8 +62,8 @@ public class ServerExecCommand extends AbstractServerCommand {
exit = -1;
}
try {
result.writeInt(exit);
result.flush();
resultStream.writeInt(exit);
resultStream.flush();
} catch (IOException e) {
// We're finished anyway
}
@ -124,9 +77,17 @@ public class ServerExecCommand extends AbstractServerCommand {
@Override
public void run() {
try {
cmd.readByte();
if (proc.isAlive()) {
proc.destroyForcibly();
switch (cmdStream.readByte()) {
case Protocol.CONTROL_KILL:
doKill(proc);
break;
case Protocol.CONTROL_SETTERMINALSIZE:
int cols = cmdStream.readInt();
int rows = cmdStream.readInt();
cmdStream.readInt(); // pixel dimensions not supported
cmdStream.readInt(); // pixel dimensions not supported
doSetTerminalSize(proc, cols, rows);
break;
}
} catch (IOException e) {
// Finish
@ -139,8 +100,7 @@ public class ServerExecCommand extends AbstractServerCommand {
private final OutputStream out;
private final String name;
private volatile boolean running = true;
private boolean terminated = false;
private boolean running = true;
private final Lock lock = new ReentrantLock();
private final Condition cond = lock.newCondition();
@ -156,58 +116,44 @@ public class ServerExecCommand extends AbstractServerCommand {
byte[] buf = new byte[8192];
int n;
try {
while (true) {
// if (in.available() == 0) {
// System.err.println("avail=0");
// /* Avoid spinning if no data */
// lock.lock();
// try {
// cond.await(100, TimeUnit.MILLISECONDS);
// } catch (InterruptedException e) {
// } finally {
// lock.unlock();
// }
// continue;
// }
while (running) {
n = in.read(buf);
if (n > 0) {
out.write(buf, 0, n);
out.flush();
}
if (n==0) System.err.println("forwarder n=0");
if (n < 0) break;
}
} catch (IOException e) {
// Finish
System.err.println("forwarder "+e.getMessage());
}
System.err.println("forwarder closing name="+name);
try {
out.close();
} catch (IOException e) {
// Best effort
}
lock.lock();
terminated = true;
try {
running = false;
try {
out.close();
} catch (IOException e) {
// Best effort
}
cond.signalAll();
} finally {
lock.unlock();
}
}
public void terminate() {
running = false;
public String getName() {
return name;
}
public synchronized void waitFor() {
lock.lock();
try {
if (!terminated) {
while (running) {
try {
cond.await();
} catch (InterruptedException e) {
// Check terminated flag
}
}
} finally {
@ -215,28 +161,71 @@ public class ServerExecCommand extends AbstractServerCommand {
}
}
}
private final List<String> command;
private final Map<String, String> env;
private final boolean redirect;
private final boolean appendEnv;
private final String directory;
private final InputStream stdinChan;
private final OutputStream stdoutChan;
private final OutputStream stderrChan;
private final DataInputStream cmdStream;
private final DataOutputStream resultStream;
public ServerExecCommand(List<String> command, Map<String, String> env, String directory, boolean redirect, boolean appendEnv, StreamChannel chanA, StreamChannel chanB, StreamChannel chanC) {
private Process proc;
public AbstractServerExecCommand(List<String> command, Map<String, String> env, String directory, boolean redirect, boolean appendEnv, StreamChannel cmdChan, StreamChannel ioChan, StreamChannel errChan) {
this.command = command;
this.env = env;
this.directory = directory;
this.redirect = redirect;
this.appendEnv = appendEnv;
this.stdin = chanA.getInputStream();
this.stdout = chanA.getOutputStream();
this.stderr = chanB.getOutputStream();
this.result = new DataOutputStream(chanC.getOutputStream());
this.cmd = new DataInputStream(chanC.getInputStream());
this.stdinChan = ioChan.getInputStream();
this.stdoutChan = ioChan.getOutputStream();
this.stderrChan = errChan != null ? errChan.getOutputStream() : this.stdoutChan;
this.resultStream = new DataOutputStream(cmdChan.getOutputStream());
this.cmdStream = new DataInputStream(cmdChan.getInputStream());
}
protected abstract Process doRun() throws IOException;
protected abstract void doKill(Process proc);
protected abstract void doSetTerminalSize(Process proc, int col, int rows);
protected List<String> getCommand() {
return command;
}
protected Map<String,String> getEnv() {
return env;
}
protected boolean isRedirect() {
return redirect;
}
protected boolean isAppendEnv() {
return appendEnv;
}
protected String getDirectory() {
return directory;
}
public void exec() throws ProxyException {
new Thread(new CommandRunner(), command.get(0)).start();
new Thread(new CommandRunner()).start();
}
private Forwarder startForwarder(String name, InputStream in, OutputStream out) {
Forwarder forwarder = new Forwarder(name, in, out);
Thread thread = new Thread(forwarder, command.get(0) + " " + name); //$NON-NLS-1$
Thread thread = new Thread(forwarder, forwarder.getName());
thread.start();
return forwarder;
}

View file

@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.commands;
package org.eclipse.remote.internal.proxy.server.core.commands;
import java.io.DataOutputStream;
import java.io.IOException;
@ -15,8 +15,8 @@ import java.net.URI;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
import org.eclipse.remote.proxy.protocol.core.SerializableFileInfo;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException;
public class ServerChildInfosCommand extends AbstractServerCommand {
@ -45,7 +45,7 @@ public class ServerChildInfosCommand extends AbstractServerCommand {
public ServerChildInfosCommand(StreamChannel chan, String path) {
this.out = chan.getOutputStream();
this.uri = URI.create("file:" + path);
this.uri = URI.create("file:" + path); //$NON-NLS-1$
}
public void exec() throws ProxyException {

View file

@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.commands;
package org.eclipse.remote.internal.proxy.server.core.commands;
import java.net.URI;
@ -20,7 +20,7 @@ public class ServerDeleteCommand extends AbstractServerCommand {
public ServerDeleteCommand(int options, String path) {
this.options = options;
this.uri = URI.create("file:" + path);
this.uri = URI.create("file:" + path); //$NON-NLS-1$
}
public void exec() throws ProxyException {

View file

@ -0,0 +1,65 @@
/*******************************************************************************
* Copyright (c) 2016 Oak Ridge National Laboratory and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.core.commands;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
/**
* TODO: Fix hang if command fails...
*
*/
public class ServerExecCommand extends AbstractServerExecCommand {
public Process doRun() throws IOException {
System.err.print("exec: ");
for (String arg:getCommand()) {
System.err.print(arg + " ");
}
System.err.println();
ProcessBuilder builder = new ProcessBuilder(getCommand());
try {
if (!isAppendEnv()) {
builder.environment().clear();
builder.environment().putAll(getEnv());
} else {
for (Map.Entry<String, String> entry : getEnv().entrySet()) {
String val = builder.environment().get(entry.getKey());
if (val == null || !val.equals(entry.getValue())) {
builder.environment().put(entry.getKey(), entry.getValue());
}
}
}
} catch (UnsupportedOperationException | IllegalArgumentException e) {
// Leave environment untouched
}
File dir = new File(getDirectory());
if (dir.exists() && dir.isAbsolute()) {
builder.directory(dir);
}
builder.redirectErrorStream(isRedirect());
return builder.start();
}
protected void doKill(Process proc) {
if (proc.isAlive()) {
proc.destroyForcibly();
}
}
protected void doSetTerminalSize(Process proc, int cols, int rows) {
// Not supported
}
public ServerExecCommand(List<String> command, Map<String, String> env, String directory, boolean redirect, boolean appendEnv, StreamChannel cmdChan, StreamChannel ioChan, StreamChannel errChan) {
super(command, env, directory, redirect, appendEnv, cmdChan, ioChan, errChan);
}
}

View file

@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.commands;
package org.eclipse.remote.internal.proxy.server.core.commands;
import java.io.DataOutputStream;
import java.io.IOException;
@ -15,8 +15,8 @@ import java.net.URI;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
import org.eclipse.remote.proxy.protocol.core.SerializableFileInfo;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException;
public class ServerFetchInfoCommand extends AbstractServerCommand {
@ -42,7 +42,7 @@ public class ServerFetchInfoCommand extends AbstractServerCommand {
public ServerFetchInfoCommand(StreamChannel chan, String path) {
this.out = chan.getOutputStream();
this.uri = URI.create("file:" + path);
this.uri = URI.create("file:" + path); //$NON-NLS-1$
}
public void exec() throws ProxyException {

View file

@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.commands;
package org.eclipse.remote.internal.proxy.server.core.commands;
import java.io.DataOutputStream;
import java.io.IOException;
@ -35,7 +35,7 @@ public class ServerGetCwdCommand extends AbstractServerCommand {
}
public void exec() throws ProxyException {
cwd = System.getProperty("user.dir");
cwd = System.getProperty("user.dir"); //$NON-NLS-1$
new Thread(new CommandRunner()).start();
}
}

View file

@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.commands;
package org.eclipse.remote.internal.proxy.server.core.commands;
import java.io.DataOutputStream;
import java.io.IOException;

View file

@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.commands;
package org.eclipse.remote.internal.proxy.server.core.commands;
import java.io.BufferedInputStream;
import java.io.IOException;

View file

@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.commands;
package org.eclipse.remote.internal.proxy.server.core.commands;
import java.io.BufferedOutputStream;
import java.io.IOException;

View file

@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.commands;
package org.eclipse.remote.internal.proxy.server.core.commands;
import java.io.DataOutputStream;
import java.io.IOException;
@ -32,7 +32,7 @@ public class ServerGetPropertiesCommand extends AbstractServerCommand {
props.put(IRemoteConnection.OS_NAME_PROPERTY, System.getProperty(IRemoteConnection.OS_NAME_PROPERTY));
props.put(IRemoteConnection.OS_VERSION_PROPERTY, System.getProperty(IRemoteConnection.OS_VERSION_PROPERTY));
props.put(IRemoteConnection.OS_ARCH_PROPERTY, System.getProperty(IRemoteConnection.OS_ARCH_PROPERTY));
props.put(IRemoteConnection.LOCALE_CHARMAP_PROPERTY, System.getProperty("file.encoding"));
props.put(IRemoteConnection.LOCALE_CHARMAP_PROPERTY, System.getProperty("file.encoding")); //$NON-NLS-1$
result.writeInt(props.size());
for (Map.Entry<String, String> entry : props.entrySet()) {

View file

@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.commands;
package org.eclipse.remote.internal.proxy.server.core.commands;
import java.net.URI;
@ -20,7 +20,7 @@ public class ServerMkdirCommand extends AbstractServerCommand {
public ServerMkdirCommand(int options, String path) {
this.options = options;
this.uri = URI.create("file:" + path);
this.uri = URI.create("file:" + path); //$NON-NLS-1$
}
public void exec() throws ProxyException {

View file

@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.commands;
package org.eclipse.remote.internal.proxy.server.core.commands;
import java.net.URI;
@ -23,7 +23,7 @@ public class ServerPutInfoCommand extends AbstractServerCommand {
public ServerPutInfoCommand(IFileInfo info, int options, String path) {
this.info = info;
this.options = options;
this.uri = URI.create("file:" + path);
this.uri = URI.create("file:" + path); //$NON-NLS-1$
}
public void exec() throws ProxyException {

View file

@ -0,0 +1,178 @@
/*******************************************************************************
* Copyright (c) 2016 Oak Ridge National Laboratory and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.remote.internal.proxy.server.core.commands;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import org.eclipse.cdt.utils.pty.PTY;
import org.eclipse.cdt.utils.pty.PTY.Mode;
import org.eclipse.cdt.utils.spawner.ProcessFactory;
import org.eclipse.remote.proxy.protocol.core.StreamChannel;
/**
* TODO: Fix hang if command fails...
*
*/
public class ServerShellCommand extends AbstractServerExecCommand {
private class ShellProcess extends Process {
private final Process proc;
private final PTY pty;
public ShellProcess(Process proc, PTY pty) {
this.proc = proc;
this.pty = pty;
}
@Override
public OutputStream getOutputStream() {
if (pty != null) {
return pty.getOutputStream();
}
return proc.getOutputStream();
}
@Override
public InputStream getInputStream() {
if (pty != null) {
return pty.getInputStream();
}
return proc.getInputStream();
}
@Override
public InputStream getErrorStream() {
if (pty != null) {
return pty.getInputStream();
}
return proc.getErrorStream();
}
@Override
public int waitFor() throws InterruptedException {
return proc.waitFor();
}
@Override
public int exitValue() {
return proc.exitValue();
}
@Override
public void destroy() {
proc.destroy();
}
public void setTerminalSize(int cols, int rows) {
if (pty != null) {
pty.setTerminalSize(cols, rows);
}
}
}
public ServerShellCommand(StreamChannel cmdChan, StreamChannel ioChan) {
super(null, null, null, true, false, cmdChan, ioChan, null);
}
public Process doRun() throws IOException {
String shell = findLoginShell();
if (PTY.isSupported(Mode.TERMINAL)) {
PTY pty = new PTY(Mode.TERMINAL);
Process p = ProcessFactory.getFactory().exec(new String[] {shell, "-l"}, null, null, pty); //$NON-NLS-1$
return new ShellProcess(p, pty);
}
return ProcessFactory.getFactory().exec(new String[] {shell, "-l"}, null, null); //$NON-NLS-1$
}
protected void doKill(Process proc) {
if (proc.isAlive()) {
proc.destroyForcibly();
}
}
protected void doSetTerminalSize(Process proc, int cols, int rows) {
if (proc.isAlive() && proc instanceof ShellProcess) {
ShellProcess shell = (ShellProcess)proc;
shell.setTerminalSize(cols, rows);
}
}
/**
* Find the login shell.
*
* On Linux, use `getent passwd $USER`
* On Mac OSX, use `dscl . -read /Users/$USER UserShell`
*
* @return
*/
private String findLoginShell() throws IOException {
String res;
String osName = System.getProperty("os.name"); //$NON-NLS-1$
String userName = System.getProperty("user.name"); //$NON-NLS-1$
if (osName == null || userName == null) {
throw new IOException("Unable to obtain information needed to find login shell"); //$NON-NLS-1$
}
switch (osName) {
case "Mac OS X": //$NON-NLS-1$
res = executeCommand("dscl . -read /Users/" + userName + " UserShell"); //$NON-NLS-1$ //$NON-NLS-2$
if (res != null) {
String[] vals = res.split(" "); //$NON-NLS-1$
if (vals.length == 2) {
return vals[1];
}
}
break;
case "Linux": //$NON-NLS-1$
res = executeCommand("getent passwd " + userName); //$NON-NLS-1$
if (res != null) {
String[] vals = res.split(":"); //$NON-NLS-1$
if (vals.length == 7) {
return vals[6];
}
}
break;
default:
break;
}
throw new IOException("Unable to find login shell for os=" + osName + " user=" + userName); //$NON-NLS-1$ //$NON-NLS-2$
}
private String executeCommand(String command) throws IOException {
String line;
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
} catch (Exception e) {
throw new IOException(e.getMessage());
}
try {
p.waitFor();
} catch (InterruptedException e) {
throw new IOException(e.getMessage());
}
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
line = reader.readLine();
while (line != null) {
output.append(line);
line = reader.readLine();
if (line != null) {
output.append("\n"); //$NON-NLS-1$
}
}
return output.toString();
}
}

View file

@ -16,7 +16,6 @@
<windowImages/>
<launcher name="proxy">
<solaris/>
<win useIco="false">
<bmp/>
</win>
@ -28,6 +27,8 @@
<plugins>
<plugin id="com.ibm.icu"/>
<plugin id="org.eclipse.cdt.core.macosx" fragment="true"/>
<plugin id="org.eclipse.cdt.core.linux.x86_64" fragment="true"/>
<plugin id="org.eclipse.cdt.core.native"/>
<plugin id="org.eclipse.core.contenttype"/>
<plugin id="org.eclipse.core.expressions"/>
@ -53,10 +54,6 @@
<plugin id="org.eclipse.remote.proxy.server.core"/>
</plugins>
<features>
<feature id="org.eclipse.remote.proxy"/>
</features>
<configurations>
<plugin id="org.eclipse.core.runtime" autoStart="true" startLevel="0" />
<plugin id="org.eclipse.equinox.common" autoStart="true" startLevel="2" />

View file

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde version="3.8"?>
<target name="remote-oxygen" sequenceNumber="0">
<?pde version="3.8"?><target name="remote-oxygen" sequenceNumber="0">
<locations>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.sdk.ide" version="0.0.0"/>
<unit id="org.eclipse.equinox.executable.feature.group" version="0.0.0"/>
<unit id="org.eclipse.sdk.ide" version="0.0.0"/>
<repository location="http://download.eclipse.org/eclipse/updates/4.7/"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.mockito" version="0.0.0"/>
<unit id="org.hamcrest" version="0.0.0"/>
<unit id="org.mockito" version="0.0.0"/>
<repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20170919201930/repository/"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.cdt.native.serial" version="0.0.0"/>
<unit id="org.eclipse.cdt.core" version="0.0.0"/>
<unit id="org.eclipse.cdt.native.feature.group" version="0.0.0"/>
<unit id="org.eclipse.cdt.native.serial" version="0.0.0"/>
<repository location="http://download.eclipse.org/tools/cdt/builds/master/nightly/"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">