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.controller.netconf.nettyutil.handler.ssh.client;
11 import io.netty.buffer.ByteBuf;
12 import io.netty.buffer.Unpooled;
13 import org.apache.sshd.common.future.SshFutureListener;
14 import org.apache.sshd.common.io.IoInputStream;
15 import org.apache.sshd.common.io.IoReadFuture;
16 import org.apache.sshd.common.util.Buffer;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
21 * Listener on async input stream from SSH session.
22 * This listeners schedules reads in a loop until the session is closed or read fails.
24 public final class AsyncSshHandlerReader implements SshFutureListener<IoReadFuture>, AutoCloseable {
26 private static final Logger logger = LoggerFactory.getLogger(AsyncSshHandler.class);
28 private static final int BUFFER_SIZE = 8192;
30 private final AutoCloseable connectionClosedCallback;
31 private final ReadMsgHandler readHandler;
33 private final String channelId;
34 private IoInputStream asyncOut;
36 private IoReadFuture currentReadFuture;
38 public AsyncSshHandlerReader(final AutoCloseable connectionClosedCallback, final ReadMsgHandler readHandler, final String channelId, final IoInputStream asyncOut) {
39 this.connectionClosedCallback = connectionClosedCallback;
40 this.readHandler = readHandler;
41 this.channelId = channelId;
42 this.asyncOut = asyncOut;
43 buf = new Buffer(BUFFER_SIZE);
44 asyncOut.read(buf).addListener(this);
48 public synchronized void operationComplete(final IoReadFuture future) {
49 if(future.getException() != null) {
50 if(asyncOut.isClosed() || asyncOut.isClosing()) {
52 logger.debug("Ssh session dropped on channel: {}", channelId, future.getException());
54 logger.warn("Exception while reading from SSH remote on channel {}", channelId, future.getException());
60 if (future.getRead() > 0) {
61 final ByteBuf msg = Unpooled.wrappedBuffer(buf.array(), 0, future.getRead());
62 if(logger.isTraceEnabled()) {
63 logger.trace("Reading message on channel: {}, message: {}", channelId, AsyncSshHandlerWriter.byteBufToString(msg));
65 readHandler.onMessageRead(msg);
68 buf = new Buffer(BUFFER_SIZE);
69 currentReadFuture = asyncOut.read(buf);
70 currentReadFuture.addListener(this);
74 private void invokeDisconnect() {
76 connectionClosedCallback.close();
77 } catch (final Exception e) {
78 // This should not happen
79 throw new IllegalStateException(e);
84 public synchronized void close() {
85 // Remove self as listener on close to prevent reading from closed input
86 if(currentReadFuture != null) {
87 currentReadFuture.removeListener(this);
88 currentReadFuture = null;
94 public interface ReadMsgHandler {
96 void onMessageRead(ByteBuf msg);