Author: gnodet
Date: Wed Oct 28 09:59:27 2009
New Revision: 830485
URL:
http://svn.apache.org/viewvc?rev=830485&view=revLog:
SSHD-22: add support for signals (slightly refactored api)
Added:
mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/Signal.java
- copied, changed from r806572, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/Signals.java
Removed:
mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/Signals.java
Modified:
mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ShellFactory.java
mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ShellFactory.java
URL:
http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ShellFactory.java?rev=830485&r1=830484&r2=830485&view=diff==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ShellFactory.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ShellFactory.java Wed Oct 28 09:59:27 2009
@@ -22,6 +22,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
+import java.util.EnumSet;
import org.apache.sshd.server.session.ServerSession;
@@ -102,9 +103,30 @@
* TODO: should we use enums for signals to allow using EnumSet or varags for
* interesting signals ?
*
- * @see Signals
+ * @see Signal
*/
public interface Environment {
+ /**
+ * Key for the user environment variable
+ */
+ public static final String ENV_USER = "USER";
+ /**
+ * Key for the lines environment variable. Specifies the number of
+ * lines visible on the client side. {@link Environment#ENV_LINES} and
+ * {@link Environment#ENV_COLUMNS} make up the console screen size.
+ */
+ public static final String ENV_LINES = "LINES";
+ /**
+ * Key for the columns environment variable. Specifies the number of
+ * columns visible on the client side. {@link Environment#ENV_LINES} and
+ * {@link Environment#ENV_COLUMNS} make up the console screen size.
+ */
+ public static final String ENV_COLUMNS = "COLUMNS";
+ /**
+ * Key for the term environment variable. Describes the terminal or
+ * terminal emulation which is in use.
+ */
+ public static final String ENV_TERM = "TERM";
/**
* Retrieve the environment map
@@ -117,24 +139,24 @@
* @param signal the signal the listener is interested in
* @param listener the listener to register
*/
- void addSignalListener(int signal, SignalListener listener);
+ void addSignalListener(Signal signal, SignalListener listener);
/**
- * Remove a previously registered listener for the specific signal
- * @param signal the signal the listener was interested in
- * @param listener the listener to unregister
+ * Add a qualified listener for the specific set of signal
+ * @param signals the signals the listener is interested in
+ * @param listener the listener to register
*/
- void removeSignalListener(int signal, SignalListener listener);
+ void addSignalListener(EnumSet<Signal> signals, SignalListener listener);
/**
- * Add a global listener
+ * Add a global listener for all signals
* @param listener the listener to register
*/
void addSignalListener(SignalListener listener);
/**
- * Remove a previously registered listener
- * @param listener
+ * Remove a previously registered listener for all the signals it was registered
+ * @param listener the listener to remove
*/
void removeSignalListener(SignalListener listener);
}
@@ -148,7 +170,7 @@
*
* @param signal
*/
- void signal(int signal);
+ void signal(Signal signal);
}
/**
Copied: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/Signal.java (from r806572, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/Signals.java)
URL:
http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/Signal.java?p2=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/Signal.java&p1=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/Signals.java&r1=806572&r2=830485&rev=830485&view=diff==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/Signals.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/Signal.java Wed Oct 28 09:59:27 2009
@@ -18,42 +18,68 @@
*/
package org.apache.sshd.server;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* System signals definition that the shell can receive.
*
* @see ShellFactory.Environment
*/
-public interface Signals {
+public enum Signal {
+
+ HUP(1),
+ INT(2),
+ QUIT(3),
+ ILL(4),
+ TRAP(5),
+ IOT(6),
+ BUS(7),
+ FPE(8),
+ KILL(9),
+ USR1(10),
+ SEGV(11),
+ USR2(12),
+ PIPE(13),
+ ALRM(14),
+ TERM(15),
+ STKFLT(16),
+ CHLD(17),
+ CONT(18),
+ STOP(19),
+ TSTP(20),
+ TTIN(21),
+ TTOU(22),
+ URG(23),
+ XCPU(24),
+ XFSZ(25),
+ VTALRM(26),
+ PROF(27),
+ WINCH(28),
+ IO(29),
+ PWR(30);
+
+ private static final Map<String, Signal> lookupTable = new HashMap<String, Signal>(40);
+
+ static {
+ // registering the signals in the lookup table to allow faster
+ // string based signal lookups
+ for (Signal s : Signal.values()) {
+ lookupTable.put(s.name(), s);
+ }
+ }
+
+ public static Signal get(String name) {
+ return lookupTable.get(name);
+ }
+
+ private final int numeric;
- public static final int SIGHUP = 1;
- public static final int SIGINT = 2;
- public static final int SIGQUIT = 3;
- public static final int SIGILL = 4;
- public static final int SIGTRAP = 5;
- public static final int SIGIOT = 6;
- public static final int SIGBUS = 7;
- public static final int SIGFPE = 8;
- public static final int SIGKILL = 9;
- public static final int SIGUSR1 = 10;
- public static final int SIGSEGV = 11;
- public static final int SIGUSR2 = 12;
- public static final int SIGPIPE = 13;
- public static final int SIGALRM = 14;
- public static final int SIGTERM = 15;
- public static final int SIGSTKFLT = 16;
- public static final int SIGCHLD = 17;
- public static final int SIGCONT = 18;
- public static final int SIGSTOP = 19;
- public static final int SIGTSTP = 20;
- public static final int SIGTTIN = 21;
- public static final int SIGTTOU = 22;
- public static final int SIGURG = 23;
- public static final int SIGXCPU = 24;
- public static final int SIGXFSZ = 25;
- public static final int SIGVTALRM = 26;
- public static final int SIGPROF = 27;
- public static final int SIGWINCH = 28;
- public static final int SIGIO = 29;
- public static final int SIGPWR = 30;
+ private Signal(int numeric) {
+ this.numeric = numeric;
+ }
+ public int getNumeric() {
+ return numeric;
+ }
}
Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
URL:
http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java?rev=830485&r1=830484&r2=830485&view=diff==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java Wed Oct 28 09:59:27 2009
@@ -22,6 +22,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -43,7 +44,7 @@
import org.apache.sshd.common.util.LoggingFilterOutputStream;
import org.apache.sshd.server.CommandFactory;
import org.apache.sshd.server.ShellFactory;
-import org.apache.sshd.server.Signals;
+import org.apache.sshd.server.Signal;
import org.apache.sshd.server.ShellFactory.Environment;
import org.apache.sshd.server.ShellFactory.SignalListener;
import org.apache.sshd.server.session.ServerSession;
@@ -68,66 +69,54 @@
protected static class StandardEnvironment implements Environment {
- private final Map<Integer, List<SignalListener>> qualifiedListeners;
- private final List<SignalListener> listeners;
+ private final Map<Signal, List<SignalListener>> listeners;
private final Map<String,String> env;
public StandardEnvironment() {
- qualifiedListeners = new ConcurrentHashMap<Integer, List<SignalListener>>(3);
- listeners = createSignalListenerList();
+ listeners = new ConcurrentHashMap<Signal, List<SignalListener>>(3);
env = new ConcurrentHashMap<String, String>();
}
- protected CopyOnWriteArrayList<SignalListener> createSignalListenerList() {
- return new CopyOnWriteArrayList<SignalListener>();
+ public void addSignalListener(Signal signal, SignalListener listener) {
+ addSignalListener(EnumSet.of(signal), listener);
}
- public void addSignalListener(int signal, SignalListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("listener may not be null");
- }
- getSignalListenersList(signal, true).add(listener);
+ public void addSignalListener(SignalListener listener) {
+ addSignalListener(EnumSet.allOf(Signal.class), listener);
}
- public void addSignalListener(SignalListener listener) {
+ public void addSignalListener(EnumSet<Signal> signals, SignalListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener may not be null");
}
- getSignalListenersList().add(listener);
+ for (Signal s : signals) {
+ getSignalListenersList(s, true).add(listener);
+ }
}
public Map<String, String> getEnv() {
return env;
}
- public void removeSignalListener(int signal, SignalListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("listener may not be null");
- }
- final List<SignalListener> ls = getSignalListenersList(signal, false);
- if (ls != null) {
- ls.remove(listener);
- }
- }
-
public void removeSignalListener(SignalListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener may not be null");
}
- getSignalListenersList().remove(listener);
+ for (Signal s : EnumSet.allOf(Signal.class)) {
+ final List<SignalListener> ls = getSignalListenersList(s, false);
+ if (ls != null) {
+ ls.remove(listener);
+ }
+ }
}
- public void signal(int signal) {
- final List<SignalListener> qls = getSignalListenersList(signal, false);
- final List<SignalListener> ls = getSignalListenersList();
- if (qls != null) {
- for(SignalListener l : qls) {
+ public void signal(Signal signal) {
+ final List<SignalListener> ls = getSignalListenersList(signal, false);
+ if (ls != null) {
+ for (SignalListener l : ls) {
l.signal(signal);
}
}
- for(SignalListener l : ls) {
- l.signal(signal);
- }
}
/**
@@ -141,23 +130,21 @@
getEnv().put(key, value);
}
- protected List<SignalListener> getSignalListenersList(int signal, boolean create) {
- List<SignalListener> ls = qualifiedListeners.get(signal);
+ protected List<SignalListener> getSignalListenersList(Signal signal, boolean create) {
+ List<SignalListener> ls = listeners.get(signal);
if (ls == null && create) {
- synchronized (qualifiedListeners) {
- ls = createSignalListenerList();
- qualifiedListeners.put(signal, ls);
+ synchronized (listeners) {
+ ls = listeners.get(signal);
+ if (ls == null) {
+ ls = new CopyOnWriteArrayList<SignalListener>();
+ listeners.put(signal, ls);
+ }
}
}
-
// may be null in case create=false
return ls;
}
- protected List<SignalListener> getSignalListenersList() {
- return listeners;
- }
-
}
protected static enum PtyMode {
@@ -367,9 +354,9 @@
}
log.debug("pty for channel {}: term={}, size=({} - {}), pixels=({}, {}), modes=[{}]", new Object[] { id, term, tColumns, tRows, tWidth, tHeight, strModes.toString() });
}
- addEnvVariable("TERM", term);
- addEnvVariable("COLUMNS", Integer.toString(tColumns));
- addEnvVariable("LINES", Integer.toString(tRows));
+ addEnvVariable(Environment.ENV_TERM, term);
+ addEnvVariable(Environment.ENV_COLUMNS, Integer.toString(tColumns));
+ addEnvVariable(Environment.ENV_LINES, Integer.toString(tRows));
// TODO: handle pty request correctly
if (wantReply) {
buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_SUCCESS);
@@ -386,12 +373,11 @@
int tWidth = buffer.getInt();
int tHeight = buffer.getInt();
log.debug("window-change for channel {}: ({} - {}), ({}, {})", new Object[] { id, tColumns, tRows, tWidth, tHeight });
- // TODO: handle window-change request correctly
final StandardEnvironment e = getEnvironment();
- e.set("COLUMNS", Integer.toString(tColumns));
- e.set("LINES", Integer.toString(tRows));
- e.signal(Signals.SIGWINCH);
+ e.set(Environment.ENV_COLUMNS, Integer.toString(tColumns));
+ e.set(Environment.ENV_LINES, Integer.toString(tRows));
+ e.signal(Signal.WINCH);
if (wantReply) {
buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_SUCCESS);
@@ -405,7 +391,15 @@
boolean wantReply = buffer.getBoolean();
String name = buffer.getString();
log.debug("Signal received on channel {}: {}", id, name);
- // TODO: handle signal request correctly
+
+ final Signal signal = Signal.get(name);
+ if (signal != null) {
+ getEnvironment().signal(signal);
+ } else {
+ log.warn("Unknown signal received: " + name);
+ }
+
+
if (wantReply) {
buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_SUCCESS);
buffer.putInt(recipient);
@@ -420,7 +414,7 @@
if (((ServerSession) session).getServerFactoryManager().getShellFactory() == null) {
return false;
}
- addEnvVariable("USER", ((ServerSession) session).getUsername());
+ addEnvVariable(Environment.ENV_USER, ((ServerSession) session).getUsername());
shell = ((ServerSession) session).getServerFactoryManager().getShellFactory().createShell();
// If the shell wants to be aware of the session, let's do that
if (shell instanceof ShellFactory.SessionAware) {