BUG-1612 Implement mina ssh netconf server endpoint
[controller.git] / opendaylight / netconf / netconf-ssh / src / main / java / org / opendaylight / controller / netconf / ssh / SshProxyClientHandler.java
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyClientHandler.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyClientHandler.java
new file mode 100644 (file)
index 0000000..2b2b3b3
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. 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.opendaylight.controller.netconf.ssh;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import org.apache.sshd.common.io.IoInputStream;
+import org.apache.sshd.common.io.IoOutputStream;
+import org.apache.sshd.server.ExitCallback;
+import org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.AsyncSshHandlerReader;
+import org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.AsyncSshHandlerWriter;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Netty handler that reads SSH from remote client and writes to delegate server and reads from delegate server and writes to remote client
+ */
+final class SshProxyClientHandler extends ChannelInboundHandlerAdapter {
+
+    private static final Logger logger = LoggerFactory.getLogger(SshProxyClientHandler.class);
+
+    private final IoInputStream in;
+    private final IoOutputStream out;
+
+    private AsyncSshHandlerReader asyncSshHandlerReader;
+    private AsyncSshHandlerWriter asyncSshHandlerWriter;
+
+    private final NetconfHelloMessageAdditionalHeader netconfHelloMessageAdditionalHeader;
+    private final ExitCallback callback;
+
+    public SshProxyClientHandler(final IoInputStream in, final IoOutputStream out,
+                                 final NetconfHelloMessageAdditionalHeader netconfHelloMessageAdditionalHeader,
+                                 final ExitCallback callback) {
+        this.in = in;
+        this.out = out;
+        this.netconfHelloMessageAdditionalHeader = netconfHelloMessageAdditionalHeader;
+        this.callback = callback;
+    }
+
+    @Override
+    public void channelActive(final ChannelHandlerContext ctx) throws Exception {
+        writeAdditionalHeader(ctx);
+
+        asyncSshHandlerWriter = new AsyncSshHandlerWriter(out);
+        asyncSshHandlerReader = new AsyncSshHandlerReader(new AutoCloseable() {
+            @Override
+            public void close() throws Exception {
+                // Close both sessions (delegate server and remote client)
+                ctx.fireChannelInactive();
+                ctx.disconnect();
+                ctx.close();
+                asyncSshHandlerReader.close();
+                asyncSshHandlerWriter.close();
+            }
+        }, new AsyncSshHandlerReader.ReadMsgHandler() {
+            @Override
+            public void onMessageRead(final ByteBuf msg) {
+                if(logger.isTraceEnabled()) {
+                    logger.trace("Forwarding message for client: {} on channel: {}, message: {}",
+                            netconfHelloMessageAdditionalHeader.getAddress(), ctx.channel(), AsyncSshHandlerWriter.byteBufToString(msg));
+                }
+                // Just forward to delegate
+                ctx.writeAndFlush(msg);
+            }
+        }, "ssh" + netconfHelloMessageAdditionalHeader.getAddress(), in);
+
+
+        super.channelActive(ctx);
+    }
+
+    private void writeAdditionalHeader(final ChannelHandlerContext ctx) {
+        ctx.writeAndFlush(Unpooled.copiedBuffer(netconfHelloMessageAdditionalHeader.toFormattedString().getBytes()));
+    }
+
+    @Override
+    public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
+       asyncSshHandlerWriter.write(ctx, msg, ctx.newPromise());
+    }
+
+    @Override
+    public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
+        logger.debug("Internal connection to netconf server was dropped for client: {} on channel: ",
+                netconfHelloMessageAdditionalHeader.getAddress(), ctx.channel());
+        callback.onExit(1, "Internal connection to netconf server was dropped for client: " +
+                netconfHelloMessageAdditionalHeader.getAddress() + " on channel: " + ctx.channel());
+        super.channelInactive(ctx);
+    }
+
+
+}