2 * Copyright (c) 2016 Brocade Communication Systems 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.callhome.protocol;
11 import com.google.common.base.Preconditions;
12 import io.netty.buffer.ByteBuf;
13 import io.netty.channel.AbstractServerChannel;
14 import io.netty.channel.ChannelConfig;
15 import io.netty.channel.ChannelHandlerContext;
16 import io.netty.channel.ChannelMetadata;
17 import io.netty.channel.ChannelOutboundBuffer;
18 import io.netty.channel.ChannelOutboundHandlerAdapter;
19 import io.netty.channel.ChannelPromise;
20 import io.netty.channel.DefaultChannelConfig;
21 import io.netty.channel.EventLoop;
22 import java.net.SocketAddress;
23 import org.apache.sshd.ClientChannel;
24 import org.apache.sshd.ClientSession;
25 import org.opendaylight.netconf.nettyutil.handler.ssh.client.AsyncSshHandlerReader;
26 import org.opendaylight.netconf.nettyutil.handler.ssh.client.AsyncSshHandlerReader.ReadMsgHandler;
27 import org.opendaylight.netconf.nettyutil.handler.ssh.client.AsyncSshHandlerWriter;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
31 class MinaSshNettyChannel extends AbstractServerChannel {
33 private static final Logger LOG = LoggerFactory.getLogger(MinaSshNettyChannel.class);
34 private static final ChannelMetadata METADATA = new ChannelMetadata(false);
35 private final ChannelConfig config = new DefaultChannelConfig(this);
36 private final CallHomeSessionContext context;
37 private final ClientSession session;
38 private final ClientChannel sshChannel;
39 private final AsyncSshHandlerReader sshReadHandler;
40 private final AsyncSshHandlerWriter sshWriteAsyncHandler;
43 private volatile boolean nettyClosed = false;
45 MinaSshNettyChannel(CallHomeSessionContext context, ClientSession session, ClientChannel sshChannel) {
46 this.context = Preconditions.checkNotNull(context);
47 this.session = Preconditions.checkNotNull(session);
48 this.sshChannel = Preconditions.checkNotNull(sshChannel);
49 this.sshReadHandler = new AsyncSshHandlerReader(new ConnectionClosedDuringRead(), new FireReadMessage(), "netconf",
50 sshChannel.getAsyncOut());
51 this.sshWriteAsyncHandler = new AsyncSshHandlerWriter(sshChannel.getAsyncIn());
52 pipeline().addFirst(createChannelAdapter());
55 private ChannelOutboundHandlerAdapter createChannelAdapter() {
56 return new ChannelOutboundHandlerAdapter() {
59 public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
60 sshWriteAsyncHandler.write(ctx, msg, promise);
67 public ChannelConfig config() {
71 private boolean notClosing(org.apache.sshd.common.Closeable sshCloseable) {
72 return !sshCloseable.isClosing() && !sshCloseable.isClosed();
77 public boolean isOpen() {
78 return notClosing(session);
82 public boolean isActive() {
83 return notClosing(session);
87 public ChannelMetadata metadata() {
92 protected AbstractUnsafe newUnsafe() {
93 return new SshUnsafe();
97 protected boolean isCompatible(EventLoop loop) {
102 protected SocketAddress localAddress0() {
103 return session.getIoSession().getLocalAddress();
107 protected SocketAddress remoteAddress0() {
108 return context.getRemoteAddress();
112 protected void doBind(SocketAddress localAddress) throws Exception {
113 throw new UnsupportedOperationException("Bind not supported.");
116 void doMinaDisconnect(boolean blocking) {
117 if(notClosing(session)) {
118 sshChannel.close(blocking);
119 session.close(blocking);
123 void doNettyDisconnect() {
126 pipeline().fireChannelInactive();
127 sshReadHandler.close();
128 sshWriteAsyncHandler.close();
133 protected void doDisconnect() throws Exception {
134 LOG.info("Disconnect invoked");
136 doMinaDisconnect(false);
140 protected void doClose() throws Exception {
141 context.removeSelf();
142 if(notClosing(session)) {
144 sshChannel.close(true);
149 protected void doBeginRead() throws Exception {
150 // Intentional NOOP - read is started by AsyncSshHandlerReader
154 protected void doWrite(ChannelOutboundBuffer in) throws Exception {
155 throw new IllegalStateException("Outbound writes to SSH should be done by SSH Write handler");
158 private final class FireReadMessage implements ReadMsgHandler {
161 public void onMessageRead(ByteBuf msg) {
162 pipeline().fireChannelRead(msg);
167 private final class ConnectionClosedDuringRead implements AutoCloseable {
170 * Invoked when SSH session dropped during read using {@link AsyncSshHandlerReader}
173 public void close() throws Exception {
179 private class SshUnsafe extends AbstractUnsafe {
182 public void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
183 throw new UnsupportedOperationException("Unsafe is not supported.");