Author: gnodet
Date: Mon Dec 22 03:49:36 2008
New Revision: 728655
URL: http://svn.apache.org/viewvc?rev=728655&view=rev
Log:
SSHD-4: Remove support for InvertedShell and provide a wrapper instead
Added:
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
(with props)
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShellWrapper.java
(with props)
Modified:
mina/sshd/trunk/src/main/java/org/apache/sshd/server/ShellFactory.java
mina/sshd/trunk/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
mina/sshd/trunk/src/test/java/org/apache/sshd/util/EchoShellFactory.java
Modified: mina/sshd/trunk/src/main/java/org/apache/sshd/server/ShellFactory.java
URL:
http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/server/ShellFactory.java?rev=728655&r1=728654&r2=728655&view=diff
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/server/ShellFactory.java
(original)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/server/ShellFactory.java Mon
Dec 22 03:49:36 2008
@@ -25,7 +25,6 @@
/**
*
- * TODO: remove InvertedShell and create a wrapper instead to keep the api
cleaner
* TODO Add javadoc
*
* @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a>
@@ -43,78 +42,12 @@
/**
* Represents a shell that can be used in an interactive mode to send
command.
- * Shell implementations must implement one of the two sub-interfaces
{...@link InvertedShell}
- * or {...@link DirectShell} which have different ways to configure the
input and output streams.
- */
- public interface Shell {
-
- /**
- * Destroy the shell.
- * This method can be called by the SSH server to destroy the shell
because
- * the client has disconnected somehow.
- */
- void destroy();
-
- }
-
- /**
- * This shell have inverted streams, such as the one obtained when
launching a
- * new {...@link Process} from java.
- */
- public interface InvertedShell extends Shell {
-
- /**
- * Starts the shell and will make the streams available for
- * the ssh server to retrieve and use.
- *
- * @param env
- * @throws Exception
- */
- void start(Map<String,String> env) throws IOException;
-
- /**
- * Returns the output stream used to feed the shell.
- * This method is called after the shell has been started.
- *
- * @return
- */
- OutputStream getInputStream();
-
- /**
- * Return an InputStream representing the output stream of the shell.
- * @return
- */
- InputStream getOutputStream();
-
- /**
- * Return an InputStream representing the error stream of the shell.
- * @return
- */
- InputStream getErrorStream();
-
- /**
- * Check if the underlying shell is still alive
- * @return
- */
- boolean isAlive();
-
- /**
- * Retrieve the exit value of the shell.
- * This method must only be called when the shell is not alive anymore.
- *
- * @return the exit value of the shell
- */
- int exitValue();
-
- }
-
- /**
* This shell have direct streams, meaning those streams will be provided
by the ssh server
- * for the shell to use directy.
- * This interface is suitable for implementing shells in java, rather than
using an external
- * process.
+ * for the shell to use directy. This interface is suitable for
implementing shells in java,
+ * rather than using an external process. For wrapping such processes or
using inverted streams,
+ * see {...@link org.apache.sshd.server.shell.InvertedShellWrapper}.
*/
- public interface DirectShell extends Shell {
+ public interface Shell {
/**
* Set the input stream that can be used by the shell to read input.
@@ -148,6 +81,13 @@
*/
void start(Map<String,String> env) throws IOException;
+ /**
+ * Destroy the shell.
+ * This method can be called by the SSH server to destroy the shell
because
+ * the client has disconnected somehow.
+ */
+ void destroy();
+
}
/**
Modified:
mina/sshd/trunk/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
URL:
http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/server/channel/ChannelSession.java?rev=728655&r1=728654&r2=728655&view=diff
==============================================================================
---
mina/sshd/trunk/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
(original)
+++
mina/sshd/trunk/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
Mon Dec 22 03:49:36 2008
@@ -126,11 +126,8 @@
protected InputStream shellOut;
protected InputStream shellErr;
protected Map<String,String> env;
- protected ExecutorService executor;
- protected boolean usePipedChannelStreams;
public ChannelSession() {
- executor = Executors.newSingleThreadExecutor();
}
public CloseFuture close(boolean immediately) {
@@ -141,7 +138,6 @@
shell = null;
}
IoUtils.closeQuietly(in, out, err, shellIn, shellOut,
shellErr);
- executor.shutdown();
}
});
}
@@ -158,26 +154,8 @@
}
protected void doWriteData(byte[] data, int off, int len) throws
IOException {
- if (usePipedChannelStreams) {
- shellIn.write(data, off, len);
- shellIn.flush();
- } else {
- final byte[] buf = new byte[len];
- System.arraycopy(data, off, buf, 0, len);
- executor.execute(new Runnable() {
- public void run() {
- try {
- if (shellIn != null) {
- shellIn.write(buf);
- shellIn.flush();
- }
- } catch (IOException e) {
- close(false);
- }
- }
- });
- localWindow.consumeAndCheck(len);
- }
+ shellIn.write(data, off, len);
+ shellIn.flush();
}
protected void doWriteExtendedData(byte[] data, int off, int len) throws
IOException {
@@ -336,38 +314,21 @@
out = new LfToCrLfFilterOutputStream(out);
err = new LfToCrLfFilterOutputStream(err);
}
- if (shell instanceof ShellFactory.InvertedShell) {
- ((ShellFactory.InvertedShell) shell).start(env);
- shellIn = ((ShellFactory.InvertedShell) shell).getInputStream();
- shellOut = ((ShellFactory.InvertedShell) shell).getOutputStream();
- shellErr = ((ShellFactory.InvertedShell) shell).getErrorStream();
- new Thread() {
- @Override
- public void run() {
- pumpStreams();
- }
- }.start();
- // TODO: set this thread as daemon?
- } else if (shell instanceof ShellFactory.DirectShell) {
- in = new ChannelPipedInputStream(localWindow);
- shellIn = new ChannelPipedOutputStream((ChannelPipedInputStream)
in);
- usePipedChannelStreams = true;
- ((ShellFactory.DirectShell) shell).setInputStream(in);
- ((ShellFactory.DirectShell) shell).setOutputStream(out);
- ((ShellFactory.DirectShell) shell).setErrorStream(err);
- ((ShellFactory.DirectShell) shell).setExitCallback(new
ShellFactory.ExitCallback() {
- public void onExit(int exitValue) {
- try {
- closeShell(exitValue);
- } catch (IOException e) {
- log.info("Error closing shell", e);
- }
+ in = new ChannelPipedInputStream(localWindow);
+ shellIn = new ChannelPipedOutputStream((ChannelPipedInputStream) in);
+ shell.setInputStream(in);
+ shell.setOutputStream(out);
+ shell.setErrorStream(err);
+ shell.setExitCallback(new ShellFactory.ExitCallback() {
+ public void onExit(int exitValue) {
+ try {
+ closeShell(exitValue);
+ } catch (IOException e) {
+ log.info("Error closing shell", e);
}
- });
- ((ShellFactory.DirectShell) shell).start(env);
- } else {
- throw new IllegalStateException("Unknown shell type");
- }
+ }
+ });
+ shell.start(env);
shellIn = new LoggingFilterOutputStream(shellIn, "IN: ", log);
if (wantReply) {
@@ -410,7 +371,6 @@
err = new LoggingFilterOutputStream(err, "ERR:", log);
in = new ChannelPipedInputStream(localWindow);
shellIn = new ChannelPipedOutputStream((ChannelPipedInputStream) in);
- usePipedChannelStreams = true;
command.setInputStream(in);
command.setOutputStream(out);
command.setErrorStream(err);
@@ -453,46 +413,6 @@
env.put(name, value);
}
- protected void pumpStreams() {
- try {
- // Use a single thread to correctly sequence the output and error
streams.
- // If any bytes are available from the output stream, send them
first, then
- // check the error stream, or wait until more data is available.
- ShellFactory.InvertedShell is = (ShellFactory.InvertedShell) shell;
- byte[] buffer = new byte[512];
- for (;;) {
- if (!is.isAlive()) {
- closeShell(is.exitValue());
- return;
- }
- if (pumpStream(shellOut, out, buffer)) {
- continue;
- }
- if (pumpStream(shellErr, err, buffer)) {
- continue;
- }
- // Sleep a bit. This is not very good, as it consumes CPU,
but the
- // input streams are not selectable for nio, and any other
blocking
- // method would consume at least two threads
- Thread.sleep(1);
- }
- } catch (Exception e) {
- session.close(false);
- }
- }
-
- private boolean pumpStream(InputStream in, OutputStream out, byte[]
buffer) throws IOException {
- if (in.available() > 0) {
- int len = in.read(buffer);
- if (len > 0) {
- out.write(buffer, 0, len);
- out.flush();
- return true;
- }
- }
- return false;
- }
-
protected void closeShell(int exitValue) throws IOException {
sendEof();
sendExitStatus(exitValue);
Added:
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
URL:
http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShell.java?rev=728655&view=auto
==============================================================================
---
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
(added)
+++
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
Mon Dec 22 03:49:36 2008
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.server.shell;
+
+import java.util.Map;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.InputStream;
+
+/**
+ * This shell have inverted streams, such as the one obtained when launching a
+ * new {...@link Process} from java. This interface is meant to be used with
+ * {...@link InvertedShellWrapper} class as an implementation of
+ * {...@link org.apache.sshd.server.ShellFactory.Shell}.
+ *
+ * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a>
+ * @version $Rev$, $Date$
+ */
+public interface InvertedShell {
+
+ /**
+ * Starts the shell and will make the streams available for
+ * the ssh server to retrieve and use.
+ *
+ * @param env
+ * @throws Exception
+ */
+ void start(Map<String,String> env) throws IOException;
+
+ /**
+ * Returns the output stream used to feed the shell.
+ * This method is called after the shell has been started.
+ *
+ * @return
+ */
+ OutputStream getInputStream();
+
+ /**
+ * Return an InputStream representing the output stream of the shell.
+ * @return
+ */
+ InputStream getOutputStream();
+
+ /**
+ * Return an InputStream representing the error stream of the shell.
+ * @return
+ */
+ InputStream getErrorStream();
+
+ /**
+ * Check if the underlying shell is still alive
+ * @return
+ */
+ boolean isAlive();
+
+ /**
+ * Retrieve the exit value of the shell.
+ * This method must only be called when the shell is not alive anymore.
+ *
+ * @return the exit value of the shell
+ */
+ int exitValue();
+
+ /**
+ * Destroy the shell.
+ * This method can be called by the SSH server to destroy the shell because
+ * the client has disconnected somehow.
+ */
+ void destroy();
+}
Propchange:
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added:
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShellWrapper.java
URL:
http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShellWrapper.java?rev=728655&view=auto
==============================================================================
---
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShellWrapper.java
(added)
+++
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShellWrapper.java
Mon Dec 22 03:49:36 2008
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.server.shell;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.sshd.server.ShellFactory;
+
+/**
+ * A shell implementation that wraps an instance of {...@link InvertedShell}
+ * as a {...@link ShellFactory.Shell}. This is useful when using external
+ * processes.
+ * When starting the shell, this wrapper will also create a thread used
+ * to pump the streams and also to check if the shell is alive.
+ *
+ * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a>
+ * @version $Rev$, $Date$
+ */
+public class InvertedShellWrapper implements ShellFactory.Shell {
+
+ private final InvertedShell shell;
+ private InputStream in;
+ private OutputStream out;
+ private OutputStream err;
+ private OutputStream shellIn;
+ private InputStream shellOut;
+ private InputStream shellErr;
+ private ShellFactory.ExitCallback callback;
+ private Thread thread;
+
+ public InvertedShellWrapper(InvertedShell shell) {
+ this.shell = shell;
+ }
+
+ public void setInputStream(InputStream in) {
+ this.in = in;
+ }
+
+ public void setOutputStream(OutputStream out) {
+ this.out = out;
+ }
+
+ public void setErrorStream(OutputStream err) {
+ this.err = err;
+ }
+
+ public void setExitCallback(ShellFactory.ExitCallback callback) {
+ this.callback = callback;
+ }
+
+ public void start(Map<String, String> env) throws IOException {
+ shell.start(env);
+ shellIn = shell.getInputStream();
+ shellOut = shell.getOutputStream();
+ shellErr = shell.getErrorStream();
+ thread = new Thread("inverted-shell-pump") {
+ @Override
+ public void run() {
+ pumpStreams();
+ }
+ };
+ thread.start();
+ }
+
+ public void destroy() {
+ shell.destroy();
+ }
+
+ protected void pumpStreams() {
+ try {
+ // Use a single thread to correctly sequence the output and error
streams.
+ // If any bytes are available from the output stream, send them
first, then
+ // check the error stream, or wait until more data is available.
+ byte[] buffer = new byte[512];
+ for (;;) {
+ if (!shell.isAlive()) {
+ callback.onExit(shell.exitValue());
+ return;
+ }
+ if (pumpStream(in, shellIn, buffer)) {
+ continue;
+ }
+ if (pumpStream(shellOut, out, buffer)) {
+ continue;
+ }
+ if (pumpStream(shellErr, err, buffer)) {
+ continue;
+ }
+ // Sleep a bit. This is not very good, as it consumes CPU,
but the
+ // input streams are not selectable for nio, and any other
blocking
+ // method would consume at least two threads
+ Thread.sleep(1);
+ }
+ } catch (Exception e) {
+ shell.destroy();
+ callback.onExit(shell.exitValue());
+ }
+ }
+
+ private boolean pumpStream(InputStream in, OutputStream out, byte[]
buffer) throws IOException {
+ if (in.available() > 0) {
+ int len = in.read(buffer);
+ if (len > 0) {
+ out.write(buffer, 0, len);
+ out.flush();
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
Propchange:
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShellWrapper.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/InvertedShellWrapper.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Modified:
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
URL:
http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java?rev=728655&r1=728654&r2=728655&view=diff
==============================================================================
---
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
(original)
+++
mina/sshd/trunk/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
Mon Dec 22 03:49:36 2008
@@ -28,7 +28,8 @@
import org.slf4j.LoggerFactory;
/**
- * TODO Add javadoc
+ * A {...@link ShellFactory} that will create a new process and bridge
+ * the streams.
*
* @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a>
* @version $Rev$, $Date$
@@ -55,7 +56,7 @@
}
public Shell createShell() {
- return new ProcessShell(command);
+ return new InvertedShellWrapper(new ProcessShell(command));
}
public static class ProcessShell implements InvertedShell {
Modified:
mina/sshd/trunk/src/test/java/org/apache/sshd/util/EchoShellFactory.java
URL:
http://svn.apache.org/viewvc/mina/sshd/trunk/src/test/java/org/apache/sshd/util/EchoShellFactory.java?rev=728655&r1=728654&r2=728655&view=diff
==============================================================================
--- mina/sshd/trunk/src/test/java/org/apache/sshd/util/EchoShellFactory.java
(original)
+++ mina/sshd/trunk/src/test/java/org/apache/sshd/util/EchoShellFactory.java
Mon Dec 22 03:49:36 2008
@@ -39,7 +39,7 @@
return new EchoShell();
}
- protected static class EchoShell implements DirectShell, Runnable {
+ protected static class EchoShell implements Shell, Runnable {
private InputStream in;
private OutputStream out;
private OutputStream err;