svn commit: r830485 - in /mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server: ShellFactory.java Signal.java Signals.java channel/ChannelSession.java

View: New views
1 Messages — Rating Filter:   Alert me  

svn commit: r830485 - in /mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server: ShellFactory.java Signal.java Signals.java channel/ChannelSession.java

by gnodet-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Author: gnodet
Date: Wed Oct 28 09:59:27 2009
New Revision: 830485

URL: http://svn.apache.org/viewvc?rev=830485&view=rev
Log:
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) {