Add workaround for SSH connection issue related to SSHD-1028
[netconf.git] / netconf / netconf-netty-util / src / main / java / org / opendaylight / netconf / nettyutil / handler / ssh / sshd1028 / NetconfNio2Session.java
1 /*
2  * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netconf.nettyutil.handler.ssh.sshd1028;
9
10 import java.io.IOException;
11 import java.net.SocketAddress;
12 import java.nio.ByteBuffer;
13 import java.nio.channels.AsynchronousSocketChannel;
14 import org.opendaylight.netconf.shaded.sshd.common.FactoryManager;
15 import org.opendaylight.netconf.shaded.sshd.common.io.IoHandler;
16 import org.opendaylight.netconf.shaded.sshd.common.io.nio2.Nio2CompletionHandler;
17 import org.opendaylight.netconf.shaded.sshd.common.io.nio2.Nio2Service;
18 import org.opendaylight.netconf.shaded.sshd.common.io.nio2.Nio2Session;
19 import org.opendaylight.netconf.shaded.sshd.common.util.Readable;
20
21 /**
22  * Custom Nio2Session which fixes the issue with connections not being properly closed.
23  * Should be removed when SSHD-1028 is fixed.
24  */
25 public class NetconfNio2Session extends Nio2Session {
26
27     public NetconfNio2Session(final Nio2Service service, final FactoryManager manager, final IoHandler handler,
28                               final AsynchronousSocketChannel socket, final SocketAddress acceptanceAddress)
29         throws IOException {
30         super(service, manager, handler, socket, acceptanceAddress);
31     }
32
33     /**
34      * This method in sshd-osgi:2.5.0 and 2.5.1 contains a bug. The close(true) statement was removed. We can override
35      * it making a workaround for this issue - until SSHD-1028 is fixed.
36      */
37     @Override
38     @SuppressWarnings("IllegalCatch")
39     protected void handleReadCycleCompletion(final ByteBuffer buffer, final Readable bufReader,
40                                              final Nio2CompletionHandler<Integer, Object> completionHandler,
41                                              final Integer result, final Object attachment) {
42         try {
43             boolean debugEnabled = log.isDebugEnabled();
44             if (result >= 0) {
45                 if (debugEnabled) {
46                     log.debug("handleReadCycleCompletion({}) read {} bytes", this, result);
47                 }
48                 buffer.flip();
49                 IoHandler handler = getIoHandler();
50                 handler.messageReceived(this, bufReader);
51                 if (!closeFuture.isClosed()) {
52                     // re-use reference for next iteration since we finished processing it
53                     buffer.clear();
54                     doReadCycle(buffer, completionHandler);
55                 } else {
56                     if (debugEnabled) {
57                         log.debug("handleReadCycleCompletion({}) IoSession has been closed, stop reading", this);
58                     }
59                 }
60             } else {
61                 if (debugEnabled) {
62                     log.debug("handleReadCycleCompletion({}) Socket has been disconnected (result={}), closing "
63                         + "IoSession now", this, result);
64                 }
65                 close(true);
66             }
67         } catch (Throwable exc) {
68             completionHandler.failed(exc, attachment);
69         }
70     }
71 }