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 {
32 private static final Logger LOG = LoggerFactory.getLogger(MinaSshNettyChannel.class);
33 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;
42 private volatile boolean nettyClosed = false;
44 MinaSshNettyChannel(CallHomeSessionContext context, ClientSession session, ClientChannel sshChannel) {
45 this.context = Preconditions.checkNotNull(context);
46 this.session = Preconditions.checkNotNull(session);
47 this.sshChannel = Preconditions.checkNotNull(sshChannel);
48 this.sshReadHandler = new AsyncSshHandlerReader(new ConnectionClosedDuringRead(), new FireReadMessage(), "netconf",
49 sshChannel.getAsyncOut());
50 this.sshWriteAsyncHandler = new AsyncSshHandlerWriter(sshChannel.getAsyncIn());
51 pipeline().addFirst(createChannelAdapter());
54 private ChannelOutboundHandlerAdapter createChannelAdapter() {
55 return new ChannelOutboundHandlerAdapter() {
58 public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
59 sshWriteAsyncHandler.write(ctx, msg, promise);
66 public ChannelConfig config() {
70 private boolean notClosing(org.apache.sshd.common.Closeable sshCloseable) {
71 return !sshCloseable.isClosing() && !sshCloseable.isClosed();
75 public boolean isOpen() {
76 return notClosing(session);
80 public boolean isActive() {
81 return notClosing(session);
85 public ChannelMetadata metadata() {
90 protected AbstractUnsafe newUnsafe() {
91 return new SshUnsafe();
95 protected boolean isCompatible(EventLoop loop) {
100 protected SocketAddress localAddress0() {
101 return session.getIoSession().getLocalAddress();
105 protected SocketAddress remoteAddress0() {
106 return context.getRemoteAddress();
110 protected void doBind(SocketAddress localAddress) throws Exception {
111 throw new UnsupportedOperationException("Bind not supported.");
114 void doMinaDisconnect(boolean blocking) {
115 if (notClosing(session)) {
116 sshChannel.close(blocking);
117 session.close(blocking);
121 void doNettyDisconnect() {
124 pipeline().fireChannelInactive();
125 sshReadHandler.close();
126 sshWriteAsyncHandler.close();
131 protected void doDisconnect() throws Exception {
132 LOG.info("Disconnect invoked");
134 doMinaDisconnect(false);
138 protected void doClose() throws Exception {
139 context.removeSelf();
140 if (notClosing(session)) {
142 sshChannel.close(true);
147 protected void doBeginRead() throws Exception {
148 // Intentional NOOP - read is started by AsyncSshHandlerReader
152 protected void doWrite(ChannelOutboundBuffer in) throws Exception {
153 throw new IllegalStateException("Outbound writes to SSH should be done by SSH Write handler");
156 private final class FireReadMessage implements ReadMsgHandler {
158 public void onMessageRead(ByteBuf msg) {
159 pipeline().fireChannelRead(msg);
163 private final class ConnectionClosedDuringRead implements AutoCloseable {
166 * Invoked when SSH session dropped during read using {@link AsyncSshHandlerReader}
169 public void close() throws Exception {
174 private class SshUnsafe extends AbstractUnsafe {
177 public void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
178 throw new UnsupportedOperationException("Unsafe is not supported.");