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.Unpooled;
12 import io.netty.channel.ChannelHandlerContext;
13 import io.netty.channel.ChannelInboundHandlerAdapter;
14 import java.nio.charset.StandardCharsets;
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(() -> {
56 // Close both sessions (delegate server and remote client)
57 ctx.fireChannelInactive();
60 asyncSshHandlerReader.close();
61 asyncSshHandlerWriter.close();
63 if (LOG.isTraceEnabled()) {
64 LOG.trace("Forwarding message for client: {} on channel: {}, message: {}",
65 netconfHelloMessageAdditionalHeader.getAddress(), ctx.channel(),
66 AsyncSshHandlerWriter.byteBufToString(msg));
68 // Just forward to delegate
69 ctx.writeAndFlush(msg);
70 }, "ssh" + netconfHelloMessageAdditionalHeader.getAddress(), in);
73 super.channelActive(ctx);
76 private void writeAdditionalHeader(final ChannelHandlerContext ctx) {
77 ctx.writeAndFlush(Unpooled.copiedBuffer(netconfHelloMessageAdditionalHeader.toFormattedString()
78 .getBytes(StandardCharsets.UTF_8)));
82 public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
83 asyncSshHandlerWriter.write(ctx, msg, ctx.newPromise());
87 public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
88 LOG.debug("Internal connection to netconf server was dropped for client: {} on channel: {}",
89 netconfHelloMessageAdditionalHeader.getAddress(), ctx.channel());
90 callback.onExit(1, "Internal connection to netconf server was dropped for client: "
91 + netconfHelloMessageAdditionalHeader.getAddress() + " on channel: " + ctx.channel());
92 super.channelInactive(ctx);