2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.netconf.ssh;
11 import io.netty.buffer.ByteBuf;
12 import io.netty.buffer.Unpooled;
13 import io.netty.channel.ChannelHandlerContext;
14 import io.netty.channel.ChannelInboundHandlerAdapter;
15 import org.apache.sshd.common.io.IoInputStream;
16 import org.apache.sshd.common.io.IoOutputStream;
17 import org.apache.sshd.server.ExitCallback;
18 import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
19 import org.opendaylight.netconf.nettyutil.handler.ssh.client.AsyncSshHandlerReader;
20 import org.opendaylight.netconf.nettyutil.handler.ssh.client.AsyncSshHandlerWriter;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
25 * Netty handler that reads SSH from remote client and writes to delegate server
26 * and reads from delegate server and writes to remote client.
28 final class SshProxyClientHandler extends ChannelInboundHandlerAdapter {
30 private static final Logger LOG = LoggerFactory.getLogger(SshProxyClientHandler.class);
32 private final IoInputStream in;
33 private final IoOutputStream out;
35 private AsyncSshHandlerReader asyncSshHandlerReader;
36 private AsyncSshHandlerWriter asyncSshHandlerWriter;
38 private final NetconfHelloMessageAdditionalHeader netconfHelloMessageAdditionalHeader;
39 private final ExitCallback callback;
41 SshProxyClientHandler(final IoInputStream in, final IoOutputStream out,
42 final NetconfHelloMessageAdditionalHeader netconfHelloMessageAdditionalHeader,
43 final ExitCallback callback) {
46 this.netconfHelloMessageAdditionalHeader = netconfHelloMessageAdditionalHeader;
47 this.callback = callback;
51 public void channelActive(final ChannelHandlerContext ctx) throws Exception {
52 writeAdditionalHeader(ctx);
54 asyncSshHandlerWriter = new AsyncSshHandlerWriter(out);
55 asyncSshHandlerReader = new AsyncSshHandlerReader(new AutoCloseable() {
57 public void close() throws Exception {
58 // Close both sessions (delegate server and remote client)
59 ctx.fireChannelInactive();
62 asyncSshHandlerReader.close();
63 asyncSshHandlerWriter.close();
65 }, new AsyncSshHandlerReader.ReadMsgHandler() {
67 public void onMessageRead(final ByteBuf msg) {
68 if (LOG.isTraceEnabled()) {
69 LOG.trace("Forwarding message for client: {} on channel: {}, message: {}",
70 netconfHelloMessageAdditionalHeader.getAddress(), ctx.channel(),
71 AsyncSshHandlerWriter.byteBufToString(msg));
73 // Just forward to delegate
74 ctx.writeAndFlush(msg);
76 }, "ssh" + netconfHelloMessageAdditionalHeader.getAddress(), in);
79 super.channelActive(ctx);
82 private void writeAdditionalHeader(final ChannelHandlerContext ctx) {
83 ctx.writeAndFlush(Unpooled.copiedBuffer(netconfHelloMessageAdditionalHeader.toFormattedString().getBytes()));
87 public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
88 asyncSshHandlerWriter.write(ctx, msg, ctx.newPromise());
92 public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
93 LOG.debug("Internal connection to netconf server was dropped for client: {} on channel: ",
94 netconfHelloMessageAdditionalHeader.getAddress(), ctx.channel());
95 callback.onExit(1, "Internal connection to netconf server was dropped for client: "
96 + netconfHelloMessageAdditionalHeader.getAddress() + " on channel: " + ctx.channel());
97 super.channelInactive(ctx);