X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fnetconf%2Fnetconf-netty-util%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fnetconf%2Fnettyutil%2Fhandler%2Fssh%2Fclient%2FAsyncSshHandler.java;h=05cd598cdc22f7b1265c661c447b850cab1a0256;hp=14d753f1f8b59c25a7ea871e3bfe5e430c1d9970;hb=9454191b8dcbbf94f422fa090690bbec0284bed6;hpb=a2563a94253f9c2603e0ab25b8f412ea07fcf51d diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandler.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandler.java index 14d753f1f8..05cd598cdc 100644 --- a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandler.java +++ b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandler.java @@ -137,7 +137,6 @@ public class AsyncSshHandler extends ChannelOutboundHandlerAdapter { LOG.trace("SSH subsystem channel opened successfully on channel: {}", ctx.channel()); connectPromise.setSuccess(); - connectPromise = null; // TODO we should also read from error stream and at least log from that @@ -162,9 +161,12 @@ public class AsyncSshHandler extends ChannelOutboundHandlerAdapter { private synchronized void handleSshSetupFailure(final ChannelHandlerContext ctx, final Throwable e) { LOG.warn("Unable to setup SSH connection on channel: {}", ctx.channel(), e); - connectPromise.setFailure(e); - connectPromise = null; - throw new IllegalStateException("Unable to setup SSH connection on channel: " + ctx.channel(), e); + disconnect(ctx, ctx.newPromise()); + + // If the promise is not yet done, we have failed with initial connect and set connectPromise to failure + if(!connectPromise.isDone()) { + connectPromise.setFailure(e); + } } @Override @@ -174,6 +176,7 @@ public class AsyncSshHandler extends ChannelOutboundHandlerAdapter { @Override public synchronized void connect(final ChannelHandlerContext ctx, final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) throws Exception { + LOG.debug("XXX session connecting on channel {}. promise: {} ", ctx.channel(), connectPromise); this.connectPromise = promise; startSsh(ctx, remoteAddress); } @@ -185,14 +188,21 @@ public class AsyncSshHandler extends ChannelOutboundHandlerAdapter { @Override public synchronized void disconnect(final ChannelHandlerContext ctx, final ChannelPromise promise) { - if(sshReadAsyncListener != null) { - sshReadAsyncListener.close(); + LOG.trace("Closing SSH session on channel: {} with connect promise in state: {}", ctx.channel(), connectPromise); + + // If we have already succeeded and the session was dropped after, we need to fire inactive to notify reconnect logic + if(connectPromise.isSuccess()) { + ctx.fireChannelInactive(); } if(sshWriteAsyncHandler != null) { sshWriteAsyncHandler.close(); } + if(sshReadAsyncListener != null) { + sshReadAsyncListener.close(); + } + if(session!= null && !session.isClosed() && !session.isClosing()) { session.close(false).addListener(new SshFutureListener() { @Override @@ -205,11 +215,19 @@ public class AsyncSshHandler extends ChannelOutboundHandlerAdapter { }); } + // Super disconnect is necessary in this case since we are using NioSocketChannel and it needs to cleanup its resources + // e.g. Socket that it tries to open in its constructor (https://bugs.opendaylight.org/show_bug.cgi?id=2430) + // TODO better solution would be to implement custom ChannelFactory + Channel that will use mina SSH lib internally: port this to custom channel implementation + try { + // Disconnect has to be closed after inactive channel event was fired, because it interferes with it + super.disconnect(ctx, ctx.newPromise()); + } catch (final Exception e) { + LOG.warn("Unable to cleanup all resources for channel: {}. Ignoring.", ctx.channel(), e); + } + channel = null; promise.setSuccess(); - LOG.debug("SSH session closed on channel: {}", ctx.channel()); - ctx.fireChannelInactive(); } }