You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2014/01/29 16:44:43 UTC

git commit: [SSHD-223] Make channel request handlers more pluggable

Updated Branches:
  refs/heads/master 488f4211f -> 36446ae8d


[SSHD-223] Make channel request handlers more pluggable

Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/36446ae8
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/36446ae8
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/36446ae8

Branch: refs/heads/master
Commit: 36446ae8df895eda196b885cb426914c384eb3fa
Parents: 488f421
Author: Guillaume Nodet <gn...@apache.org>
Authored: Wed Jan 29 16:44:36 2014 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Wed Jan 29 16:44:36 2014 +0100

----------------------------------------------------------------------
 .../main/java/org/apache/sshd/SshServer.java    |  5 +-
 .../agent/local/ChannelAgentForwarding.java     |  6 ---
 .../sshd/agent/unix/ChannelAgentForwarding.java |  6 ---
 .../client/channel/AbstractClientChannel.java   | 40 +++++++++------
 .../sshd/common/AbstractFactoryManager.java     |  9 ++--
 .../java/org/apache/sshd/common/Channel.java    |  2 +-
 .../org/apache/sshd/common/FactoryManager.java  |  5 +-
 .../sshd/common/GlobalRequestHandler.java       | 45 -----------------
 .../org/apache/sshd/common/RequestHandler.java  | 52 ++++++++++++++++++++
 .../sshd/common/channel/AbstractChannel.java    | 47 +++++++++++++++++-
 .../sshd/common/forward/TcpipServerChannel.java |  5 --
 .../session/AbstractConnectionService.java      | 44 +++++++++--------
 .../sshd/server/channel/ChannelSession.java     | 18 +++++--
 .../global/CancelTcpipForwardHandler.java       | 10 ++--
 .../sshd/server/global/KeepAliveHandler.java    | 14 ++----
 .../server/global/NoMoreSessionsHandler.java    | 14 ++----
 .../sshd/server/global/TcpipForwardHandler.java | 10 ++--
 .../server/session/ServerConnectionService.java |  9 ----
 18 files changed, 190 insertions(+), 151 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/SshServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/SshServer.java b/sshd-core/src/main/java/org/apache/sshd/SshServer.java
index 90df02d..de45dff 100644
--- a/sshd-core/src/main/java/org/apache/sshd/SshServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/SshServer.java
@@ -41,7 +41,7 @@ import org.apache.sshd.common.Cipher;
 import org.apache.sshd.common.Compression;
 import org.apache.sshd.common.Factory;
 import org.apache.sshd.common.ForwardingFilter;
-import org.apache.sshd.common.GlobalRequestHandler;
+import org.apache.sshd.common.RequestHandler;
 import org.apache.sshd.common.KeyExchange;
 import org.apache.sshd.common.Mac;
 import org.apache.sshd.common.NamedFactory;
@@ -79,6 +79,7 @@ import org.apache.sshd.common.random.BouncyCastleRandom;
 import org.apache.sshd.common.random.JceRandom;
 import org.apache.sshd.common.random.SingletonRandomFactory;
 import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.session.ConnectionService;
 import org.apache.sshd.common.signature.SignatureDSA;
 import org.apache.sshd.common.signature.SignatureECDSA;
 import org.apache.sshd.common.signature.SignatureRSA;
@@ -500,7 +501,7 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
                 new TcpipServerChannel.DirectTcpipFactory()));
         sshd.setFileSystemFactory(new NativeFileSystemFactory());
         sshd.setTcpipForwarderFactory(new DefaultTcpipForwarderFactory());
-        sshd.setGlobalRequestHandlers(Arrays.<GlobalRequestHandler>asList(
+        sshd.setGlobalRequestHandlers(Arrays.<RequestHandler<ConnectionService>>asList(
                 new KeepAliveHandler(),
                 new NoMoreSessionsHandler(),
                 new TcpipForwardHandler(),

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
index bdd5165..61aea86 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
@@ -111,12 +111,6 @@ public class ChannelAgentForwarding extends AbstractServerChannel {
         throw new UnsupportedOperationException("AgentForward channel does not support extended data");
     }
 
-    public boolean handleRequest(String type, Buffer buffer) throws IOException {
-        log.info("Received SSH_MSG_CHANNEL_REQUEST on channel {}", id);
-        log.info("Received channel request: {}", type);
-        return false;
-    }
-
     protected class AgentClient extends AbstractAgentClient {
 
         public AgentClient() {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java b/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java
index 84f32f4..5dff9db 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java
@@ -137,12 +137,6 @@ public class ChannelAgentForwarding extends AbstractServerChannel {
         throw new UnsupportedOperationException("AgentForward channel does not support extended data");
     }
 
-    public boolean handleRequest(String type, Buffer buffer) throws IOException {
-        log.info("Received SSH_MSG_CHANNEL_REQUEST on channel {}", id);
-        log.info("Received channel request: {}", type);
-        return false;
-    }
-
     /**
      * transform an APR error number in a more fancy exception
      * @param code APR error code

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
index fd5e180..84c0a06 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
@@ -25,6 +25,8 @@ import java.io.OutputStream;
 import org.apache.sshd.ClientChannel;
 import org.apache.sshd.client.future.DefaultOpenFuture;
 import org.apache.sshd.client.future.OpenFuture;
+import org.apache.sshd.common.Channel;
+import org.apache.sshd.common.RequestHandler;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.channel.AbstractChannel;
@@ -56,6 +58,8 @@ public abstract class AbstractClientChannel extends AbstractChannel implements C
 
     protected AbstractClientChannel(String type) {
         this.type = type;
+        addRequestHandler(new ExitStatusChannelRequestHandler());
+        addRequestHandler(new ExitSignalChannelRequestHandler());
     }
 
     public OutputStream getInvertedIn() {
@@ -250,22 +254,30 @@ public abstract class AbstractClientChannel extends AbstractChannel implements C
         localWindow.consumeAndCheck(len);
     }
 
-    public boolean handleRequest(String req, Buffer buffer) throws IOException {
-        log.info("Received SSH_MSG_CHANNEL_REQUEST {} on channel {}", req, id);
-        if ("exit-status".equals(req)) {
-            exitStatus = buffer.getInt();
-            notifyStateChanged();
-            return true;
-        } else if ("exit-signal".equals(req)) {
-            exitSignal = buffer.getString();
-            notifyStateChanged();
-            return true;
+    public Integer getExitStatus() {
+        return exitStatus;
+    }
+
+    private class ExitStatusChannelRequestHandler implements RequestHandler<Channel> {
+        public Result process(Channel channel, String request, boolean wantReply, Buffer buffer) throws Exception {
+            if (request.equals("exit-status")) {
+                exitStatus = buffer.getInt();
+                notifyStateChanged();
+                return Result.ReplySuccess;
+            }
+            return Result.Unsupported;
         }
-        // TODO: handle other channel requests
-        return false;
     }
 
-    public Integer getExitStatus() {
-        return exitStatus;
+    private class ExitSignalChannelRequestHandler implements RequestHandler<Channel> {
+        public Result process(Channel channel, String request, boolean wantReply, Buffer buffer) throws Exception {
+            if (request.equals("exit-signal")) {
+                exitSignal = buffer.getString();
+                notifyStateChanged();
+                return Result.ReplySuccess;
+            }
+            return Result.Unsupported;
+        }
     }
+
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
index 6c5bf4f..fd7d48c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
@@ -27,9 +27,8 @@ import java.util.concurrent.ScheduledExecutorService;
 
 import org.apache.sshd.agent.SshAgentFactory;
 import org.apache.sshd.common.file.FileSystemFactory;
-import org.apache.sshd.common.io.IoAcceptor;
-import org.apache.sshd.common.io.IoConnector;
 import org.apache.sshd.common.io.IoServiceFactory;
+import org.apache.sshd.common.session.ConnectionService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -60,7 +59,7 @@ public abstract class AbstractFactoryManager implements FactoryManager {
     protected ForwardingFilter tcpipForwardingFilter;
     protected FileSystemFactory fileSystemFactory;
     protected List<ServiceFactory> serviceFactories;
-    protected List<GlobalRequestHandler> globalRequestHandlers;
+    protected List<RequestHandler<ConnectionService>> globalRequestHandlers;
 
     protected AbstractFactoryManager() {
         loadVersion();
@@ -238,11 +237,11 @@ public abstract class AbstractFactoryManager implements FactoryManager {
         this.serviceFactories = serviceFactories;
     }
 
-    public List<GlobalRequestHandler> getGlobalRequestHandlers() {
+    public List<RequestHandler<ConnectionService>> getGlobalRequestHandlers() {
         return globalRequestHandlers;
     }
 
-    public void setGlobalRequestHandlers(List<GlobalRequestHandler> globalRequestHandlers) {
+    public void setGlobalRequestHandlers(List<RequestHandler<ConnectionService>> globalRequestHandlers) {
         this.globalRequestHandlers = globalRequestHandlers;
     }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/common/Channel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/Channel.java b/sshd-core/src/main/java/org/apache/sshd/common/Channel.java
index aceaef3..684898f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/Channel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/Channel.java
@@ -47,7 +47,7 @@ public interface Channel {
 
     void handleWindowAdjust(Buffer buffer) throws IOException;
 
-    boolean handleRequest(String type, Buffer buffer) throws IOException;
+    void handleRequest(Buffer buffer) throws IOException;
 
     void handleData(Buffer buffer) throws IOException;
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
index 43df005..a06a13f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
@@ -24,9 +24,8 @@ import java.util.concurrent.ScheduledExecutorService;
 
 import org.apache.sshd.agent.SshAgentFactory;
 import org.apache.sshd.common.file.FileSystemFactory;
-import org.apache.sshd.common.io.IoAcceptor;
-import org.apache.sshd.common.io.IoConnector;
 import org.apache.sshd.common.io.IoServiceFactory;
+import org.apache.sshd.common.session.ConnectionService;
 
 /**
  * This interface allows retrieving all the <code>NamedFactory</code> used
@@ -189,6 +188,6 @@ public interface FactoryManager {
      *
      * @return a list of named <code>GlobalRequestHandler</code>
      */
-    List<GlobalRequestHandler> getGlobalRequestHandlers();
+    List<RequestHandler<ConnectionService>> getGlobalRequestHandlers();
 
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/common/GlobalRequestHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/GlobalRequestHandler.java b/sshd-core/src/main/java/org/apache/sshd/common/GlobalRequestHandler.java
deleted file mode 100644
index 5409a4f..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/GlobalRequestHandler.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.common;
-
-import org.apache.sshd.common.session.ConnectionService;
-import org.apache.sshd.common.util.Buffer;
-
-/**
- * A global request handler.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public interface GlobalRequestHandler {
-
-    /**
-     * Process the ssh-connection global request.
-     * If an exception is thrown, the ConnectionService will send a failure message if needed
-     * and the request will be considered handled.
-     *
-     * @param connectionService
-     * @param request
-     * @param wantReply
-     * @param buffer
-     * @return <code>true</code> if the request was handled
-     * @throws Exception
-     */
-    boolean process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception;
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/common/RequestHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/RequestHandler.java b/sshd-core/src/main/java/org/apache/sshd/common/RequestHandler.java
new file mode 100644
index 0000000..1a239c4
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/RequestHandler.java
@@ -0,0 +1,52 @@
+/*
+ * 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.common;
+
+import org.apache.sshd.common.session.ConnectionService;
+import org.apache.sshd.common.util.Buffer;
+
+/**
+ * A global request handler.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface RequestHandler<T> {
+
+    enum Result {
+        Unsupported,
+        Replied,
+        ReplySuccess,
+        ReplyFailure
+    }
+
+    /**
+     * Process the ssh-connection global request.
+     * If an exception is thrown, the ConnectionService will send a failure message if needed
+     * and the request will be considered handled.
+     *
+     * @param t
+     * @param request
+     * @param wantReply
+     * @param buffer
+     * @return
+     * @throws Exception
+     */
+    Result process(T t, String request, boolean wantReply, Buffer buffer) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
index 05b633a..4e610bb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
@@ -19,10 +19,13 @@
 package org.apache.sshd.common.channel;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.sshd.common.Channel;
 import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.RequestHandler;
 import org.apache.sshd.common.Session;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.future.CloseFuture;
@@ -57,6 +60,11 @@ public abstract class AbstractChannel implements Channel {
     protected volatile boolean eof;
     protected final AtomicBoolean closing = new AtomicBoolean();
     protected boolean closedByOtherSide;
+    protected final List<RequestHandler<Channel>> handlers = new ArrayList<RequestHandler<Channel>>();
+
+    public void addRequestHandler(RequestHandler<Channel> handler) {
+        handlers.add(handler);
+    }
 
     public int getId() {
         return id;
@@ -78,8 +86,43 @@ public abstract class AbstractChannel implements Channel {
         return session;
     }
 
-    public boolean handleRequest(String type, Buffer buffer) throws IOException {
-        throw new IllegalStateException();
+    public void handleRequest(Buffer buffer) throws IOException {
+        String req = buffer.getString();
+        boolean wantReply = buffer.getBoolean();
+        log.debug("Received SSH_MSG_CHANNEL_REQUEST {} on channel {} (wantReply {})", new Object[] { req, id, wantReply });
+        for (RequestHandler<Channel> handler : handlers) {
+            RequestHandler.Result result;
+            try {
+                result = handler.process(this, req, wantReply, buffer);
+            } catch (Exception e) {
+                log.warn("Error processing channel request " + req, e);
+                result = RequestHandler.Result.ReplyFailure;
+            }
+            switch (result) {
+                case Replied:
+                    return;
+                case ReplySuccess:
+                    if (wantReply) {
+                        buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_SUCCESS, 0);
+                        buffer.putInt(recipient);
+                        session.writePacket(buffer);
+                    }
+                    return;
+                case ReplyFailure:
+                    if (wantReply) {
+                        buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_FAILURE, 0);
+                        buffer.putInt(recipient);
+                        session.writePacket(buffer);
+                    }
+                    return;
+            }
+        }
+        log.warn("Unknown channel request: {}", req);
+        if (wantReply) {
+            buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_FAILURE, 0);
+            buffer.putInt(recipient);
+            session.writePacket(buffer);
+        }
     }
 
     public void init(ConnectionService service, Session session, int id) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipServerChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipServerChannel.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipServerChannel.java
index 2e98811..48ee313 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipServerChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipServerChannel.java
@@ -190,9 +190,4 @@ public class TcpipServerChannel extends AbstractServerChannel {
         throw new UnsupportedOperationException(type + "Tcpip channel does not support extended data");
     }
 
-    public boolean handleRequest(String type, Buffer buffer) throws IOException {
-        log.info("Received SSH_MSG_CHANNEL_REQUEST on channel {}", id);
-        log.info("Received channel request: {}", type);
-        return false;
-    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java
index 54432a8..0149adb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java
@@ -29,7 +29,7 @@ import org.apache.sshd.agent.common.AgentForwardSupport;
 import org.apache.sshd.client.channel.AbstractClientChannel;
 import org.apache.sshd.client.future.OpenFuture;
 import org.apache.sshd.common.Channel;
-import org.apache.sshd.common.GlobalRequestHandler;
+import org.apache.sshd.common.RequestHandler;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.Session;
 import org.apache.sshd.common.SshConstants;
@@ -275,16 +275,7 @@ public abstract class AbstractConnectionService implements ConnectionService {
      */
     public void channelRequest(Buffer buffer) throws IOException {
         Channel channel = getChannel(buffer);
-        String type = buffer.getString();
-        boolean wantReply = buffer.getBoolean();
-        boolean success = channel.handleRequest(type, buffer);
-        if (wantReply) {
-            Buffer replyBuffer = session.createBuffer(
-                    success ? SshConstants.Message.SSH_MSG_CHANNEL_SUCCESS
-                            : SshConstants.Message.SSH_MSG_CHANNEL_FAILURE, 0);
-            replyBuffer.putInt(channel.getRecipient());
-            session.writePacket(replyBuffer);
-        }
+        channel.handleRequest(buffer);
     }
 
     /**
@@ -395,20 +386,31 @@ public abstract class AbstractConnectionService implements ConnectionService {
         String req = buffer.getString();
         boolean wantReply = buffer.getBoolean();
         log.debug("Received SSH_MSG_GLOBAL_REQUEST {}", req);
-        List<GlobalRequestHandler> handlers = session.getFactoryManager().getGlobalRequestHandlers();
+        List<RequestHandler<ConnectionService>> handlers = session.getFactoryManager().getGlobalRequestHandlers();
         if (handlers != null) {
-            for (GlobalRequestHandler handler : handlers) {
+            for (RequestHandler<ConnectionService> handler : handlers) {
+                RequestHandler.Result result;
                 try {
-                    if (handler.process(this, req, wantReply, buffer)) {
-                        return;
-                    }
+                    result = handler.process(this, req, wantReply, buffer);
                 } catch (Exception e) {
                     log.warn("Error processing global request " + req, e);
-                    if (wantReply) {
-                        buffer = session.createBuffer(SshConstants.Message.SSH_MSG_REQUEST_FAILURE, 0);
-                        session.writePacket(buffer);
-                    }
-                    return;
+                    result = RequestHandler.Result.ReplyFailure;
+                }
+                switch (result) {
+                    case Replied:
+                        return;
+                    case ReplySuccess:
+                        if (wantReply) {
+                            buffer = session.createBuffer(SshConstants.Message.SSH_MSG_REQUEST_SUCCESS, 0);
+                            session.writePacket(buffer);
+                        }
+                        return;
+                    case ReplyFailure:
+                        if (wantReply) {
+                            buffer = session.createBuffer(SshConstants.Message.SSH_MSG_REQUEST_FAILURE, 0);
+                            session.writePacket(buffer);
+                        }
+                        return;
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
index 638dfcb..86e6ea6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
@@ -36,6 +36,7 @@ import org.apache.sshd.common.Channel;
 import org.apache.sshd.common.ForwardingFilter;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.PtyMode;
+import org.apache.sshd.common.RequestHandler;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.channel.ChannelOutputStream;
 import org.apache.sshd.common.future.CloseFuture;
@@ -180,6 +181,7 @@ public class ChannelSession extends AbstractServerChannel {
     protected final CloseFuture commandExitFuture = new DefaultCloseFuture(lock);
 
     public ChannelSession() {
+        addRequestHandler(new ChannelSessionRequestHandler());
     }
 
     @Override
@@ -253,9 +255,7 @@ public class ChannelSession extends AbstractServerChannel {
         throw new UnsupportedOperationException("Server channel does not support extended data");
     }
 
-    public boolean handleRequest(String type, Buffer buffer) throws IOException {
-        log.debug("Received SSH_MSG_CHANNEL_REQUEST on channel {}", id);
-        log.debug("Received channel request: {}", type);
+    public Boolean handleRequest(String type, Buffer buffer) throws IOException {
         if ("env".equals(type)) {
             return handleEnv(buffer);
         }
@@ -301,7 +301,7 @@ public class ChannelSession extends AbstractServerChannel {
         if ("x11-req".equals(type)) {
             return handleX11Forwarding(buffer);
         }
-        return false;
+        return null;
     }
 
     protected boolean handleEnv(Buffer buffer) throws IOException {
@@ -533,4 +533,14 @@ public class ChannelSession extends AbstractServerChannel {
         commandExitFuture.setClosed();
     }
 
+    private class ChannelSessionRequestHandler implements RequestHandler<Channel> {
+        public Result process(Channel channel, String request, boolean wantReply, Buffer buffer) throws Exception {
+            Boolean r = handleRequest(request, buffer);
+            if (r == null) {
+                return Result.Unsupported;
+            } else {
+                return r ? Result.ReplySuccess : Result.ReplyFailure;
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
index 23c127d..75fea9f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
@@ -18,7 +18,7 @@
  */
 package org.apache.sshd.server.global;
 
-import org.apache.sshd.common.GlobalRequestHandler;
+import org.apache.sshd.common.RequestHandler;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshdSocketAddress;
 import org.apache.sshd.common.session.ConnectionService;
@@ -29,9 +29,9 @@ import org.apache.sshd.common.util.Buffer;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class CancelTcpipForwardHandler implements GlobalRequestHandler {
+public class CancelTcpipForwardHandler implements RequestHandler<ConnectionService> {
 
-    public boolean process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception {
+    public Result process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception {
         if (request.equals("cancel-tcpip-forward")) {
             String address = buffer.getString();
             int port = buffer.getInt();
@@ -41,9 +41,9 @@ public class CancelTcpipForwardHandler implements GlobalRequestHandler {
                 buffer.putInt(port);
                 connectionService.getSession().writePacket(buffer);
             }
-            return true;
+            return Result.Replied;
         }
-        return false;
+        return Result.Unsupported;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/server/global/KeepAliveHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/KeepAliveHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/KeepAliveHandler.java
index 3371ed9..20ab0b9 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/global/KeepAliveHandler.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/global/KeepAliveHandler.java
@@ -18,7 +18,7 @@
  */
 package org.apache.sshd.server.global;
 
-import org.apache.sshd.common.GlobalRequestHandler;
+import org.apache.sshd.common.RequestHandler;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.session.ConnectionService;
 import org.apache.sshd.common.util.Buffer;
@@ -28,17 +28,13 @@ import org.apache.sshd.common.util.Buffer;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class KeepAliveHandler implements GlobalRequestHandler {
+public class KeepAliveHandler implements RequestHandler<ConnectionService> {
 
-    public boolean process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception {
+    public Result process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception {
         if (request.startsWith("keepalive@")) {
-            if (wantReply) {
-                buffer = connectionService.getSession().createBuffer(SshConstants.Message.SSH_MSG_REQUEST_FAILURE, 0);
-                connectionService.getSession().writePacket(buffer);
-            }
-            return true;
+            return Result.ReplyFailure;
         }
-        return false;
+        return Result.Unsupported;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/server/global/NoMoreSessionsHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/NoMoreSessionsHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/NoMoreSessionsHandler.java
index 98fe3a3..bfd5b26 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/global/NoMoreSessionsHandler.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/global/NoMoreSessionsHandler.java
@@ -18,7 +18,7 @@
  */
 package org.apache.sshd.server.global;
 
-import org.apache.sshd.common.GlobalRequestHandler;
+import org.apache.sshd.common.RequestHandler;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.session.ConnectionService;
 import org.apache.sshd.common.util.Buffer;
@@ -28,18 +28,14 @@ import org.apache.sshd.common.util.Buffer;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class NoMoreSessionsHandler implements GlobalRequestHandler {
+public class NoMoreSessionsHandler implements RequestHandler<ConnectionService> {
 
-    public boolean process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception {
+    public Result process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception {
         if (request.startsWith("no-more-sessions@")) {
             connectionService.setAllowMoreSessions(false);
-            if (wantReply) {
-                buffer = connectionService.getSession().createBuffer(SshConstants.Message.SSH_MSG_REQUEST_FAILURE, 0);
-                connectionService.getSession().writePacket(buffer);
-            }
-            return true;
+            return Result.ReplyFailure;
         }
-        return false;
+        return Result.Unsupported;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
index 01aa6a5..e94a197 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
@@ -18,7 +18,7 @@
  */
 package org.apache.sshd.server.global;
 
-import org.apache.sshd.common.GlobalRequestHandler;
+import org.apache.sshd.common.RequestHandler;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshdSocketAddress;
 import org.apache.sshd.common.session.ConnectionService;
@@ -29,9 +29,9 @@ import org.apache.sshd.common.util.Buffer;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class TcpipForwardHandler implements GlobalRequestHandler {
+public class TcpipForwardHandler implements RequestHandler<ConnectionService> {
 
-    public boolean process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception {
+    public Result process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception {
         if (request.equals("tcpip-forward")) {
             String address = buffer.getString();
             int port = buffer.getInt();
@@ -42,9 +42,9 @@ public class TcpipForwardHandler implements GlobalRequestHandler {
                 buffer.putInt(port);
                 connectionService.getSession().writePacket(buffer);
             }
-            return true;
+            return Result.Replied;
         }
-        return false;
+        return Result.Unsupported;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/36446ae8/sshd-core/src/main/java/org/apache/sshd/server/session/ServerConnectionService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerConnectionService.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerConnectionService.java
index 50c0cf8..101b5a5 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerConnectionService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerConnectionService.java
@@ -20,20 +20,11 @@ package org.apache.sshd.server.session;
 
 import java.io.IOException;
 
-import org.apache.sshd.client.future.OpenFuture;
-import org.apache.sshd.common.Channel;
-import org.apache.sshd.common.GlobalRequestHandler;
-import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.Service;
 import org.apache.sshd.common.ServiceFactory;
 import org.apache.sshd.common.Session;
-import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.SshdSocketAddress;
-import org.apache.sshd.common.future.SshFutureListener;
 import org.apache.sshd.common.session.AbstractConnectionService;
-import org.apache.sshd.common.util.Buffer;
-import org.apache.sshd.server.channel.OpenChannelException;
 
 /**
  * Server side <code>ssh-connection</code> service.