/* * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.netconf.nettyutil.handler.ssh.sshd1028; import java.io.IOException; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import org.opendaylight.netconf.shaded.sshd.common.FactoryManager; import org.opendaylight.netconf.shaded.sshd.common.io.IoHandler; import org.opendaylight.netconf.shaded.sshd.common.io.nio2.Nio2CompletionHandler; import org.opendaylight.netconf.shaded.sshd.common.io.nio2.Nio2Service; import org.opendaylight.netconf.shaded.sshd.common.io.nio2.Nio2Session; import org.opendaylight.netconf.shaded.sshd.common.util.Readable; /** * Custom Nio2Session which fixes the issue with connections not being properly closed. * Should be removed when SSHD-1028 is fixed. */ public class NetconfNio2Session extends Nio2Session { public NetconfNio2Session(final Nio2Service service, final FactoryManager manager, final IoHandler handler, final AsynchronousSocketChannel socket, final SocketAddress acceptanceAddress) throws IOException { super(service, manager, handler, socket, acceptanceAddress); } /** * This method in sshd-osgi:2.5.0 and 2.5.1 contains a bug. The close(true) statement was removed. We can override * it making a workaround for this issue - until SSHD-1028 is fixed. */ @Override @SuppressWarnings("IllegalCatch") protected void handleReadCycleCompletion(final ByteBuffer buffer, final Readable bufReader, final Nio2CompletionHandler completionHandler, final Integer result, final Object attachment) { try { boolean debugEnabled = log.isDebugEnabled(); if (result >= 0) { if (debugEnabled) { log.debug("handleReadCycleCompletion({}) read {} bytes", this, result); } buffer.flip(); IoHandler handler = getIoHandler(); handler.messageReceived(this, bufReader); if (!closeFuture.isClosed()) { // re-use reference for next iteration since we finished processing it buffer.clear(); doReadCycle(buffer, completionHandler); } else { if (debugEnabled) { log.debug("handleReadCycleCompletion({}) IoSession has been closed, stop reading", this); } } } else { if (debugEnabled) { log.debug("handleReadCycleCompletion({}) Socket has been disconnected (result={}), closing " + "IoSession now", this, result); } close(true); } } catch (Throwable exc) { completionHandler.failed(exc, attachment); } } }