From d6e85d5522bbc0045706c7dd48288d0dcaf4b831 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 17 Aug 2012 17:33:06 +0200 Subject: [PATCH] SSH: Take more care when closing channels. We can't just pretend a channel is already gone after we request it to close; it's only closed when the server has sent the acknowledgement. Change-Id: Ib6e8b9bf77635995259885af13755f5fc0e825a9 Reviewed-by: Tobias Hunger --- src/libs/ssh/sshchannelmanager.cpp | 13 ++++++++++--- src/libs/ssh/sshchannelmanager_p.h | 5 ++++- src/libs/ssh/sshconnection.cpp | 9 +++++++-- src/libs/ssh/sshconnection.h | 2 ++ src/libs/ssh/sshconnectionmanager.cpp | 2 ++ 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/libs/ssh/sshchannelmanager.cpp b/src/libs/ssh/sshchannelmanager.cpp index dbae05e06c..792963702e 100644 --- a/src/libs/ssh/sshchannelmanager.cpp +++ b/src/libs/ssh/sshchannelmanager.cpp @@ -176,16 +176,23 @@ void SshChannelManager::insertChannel(AbstractSshChannel *priv, m_sessions.insert(priv, pub); } -int SshChannelManager::closeAllChannels() +int SshChannelManager::closeAllChannels(CloseAllMode mode) { const int count = m_channels.count(); for (ChannelIterator it = m_channels.begin(); it != m_channels.end(); ++it) it.value()->closeChannel(); - m_channels.clear(); - m_sessions.clear(); + if (mode == CloseAllAndReset) { + m_channels.clear(); + m_sessions.clear(); + } return count; } +int SshChannelManager::channelCount() const +{ + return m_channels.count(); +} + void SshChannelManager::removeChannel(ChannelIterator it) { Q_ASSERT(it != m_channels.end() && "Unexpected channel lookup failure."); diff --git a/src/libs/ssh/sshchannelmanager_p.h b/src/libs/ssh/sshchannelmanager_p.h index 29589f6da7..16626eddb1 100644 --- a/src/libs/ssh/sshchannelmanager_p.h +++ b/src/libs/ssh/sshchannelmanager_p.h @@ -55,7 +55,10 @@ public: QSharedPointer createRemoteProcess(const QByteArray &command); QSharedPointer createRemoteShell(); QSharedPointer createSftpChannel(); - int closeAllChannels(); + int channelCount() const; + + enum CloseAllMode { CloseAllRegular, CloseAllAndReset }; + int closeAllChannels(CloseAllMode mode); void handleChannelRequest(const SshIncomingPacket &packet); void handleChannelOpen(const SshIncomingPacket &packet); diff --git a/src/libs/ssh/sshconnection.cpp b/src/libs/ssh/sshconnection.cpp index 7e1a842823..ebf233d3b6 100644 --- a/src/libs/ssh/sshconnection.cpp +++ b/src/libs/ssh/sshconnection.cpp @@ -194,13 +194,18 @@ QSharedPointer SshConnection::createSftpChannel() int SshConnection::closeAllChannels() { try { - return d->m_channelManager->closeAllChannels(); + return d->m_channelManager->closeAllChannels(Internal::SshChannelManager::CloseAllRegular); } catch (const Botan::Exception &e) { qDebug("%s: %s", Q_FUNC_INFO, e.what()); return -1; } } +int SshConnection::channelCount() const +{ + return d->m_channelManager->channelCount(); +} + namespace Internal { SshConnectionPrivate::SshConnectionPrivate(SshConnection *conn, @@ -680,7 +685,7 @@ void SshConnectionPrivate::closeConnection(SshErrorCode sshError, m_keepAliveTimer.stop(); disconnect(&m_keepAliveTimer, 0, this, 0); try { - m_channelManager->closeAllChannels(); + m_channelManager->closeAllChannels(SshChannelManager::CloseAllAndReset); m_sendFacility.sendDisconnectPacket(sshError, serverErrorString); } catch (Botan::Exception &) {} // Nothing sensible to be done here. if (m_error != SshNoError) diff --git a/src/libs/ssh/sshconnection.h b/src/libs/ssh/sshconnection.h index 1e8d7effa8..66263c3077 100644 --- a/src/libs/ssh/sshconnection.h +++ b/src/libs/ssh/sshconnection.h @@ -107,6 +107,8 @@ public: // -1 if an error occurred, number of channels closed otherwise. int closeAllChannels(); + int channelCount() const; + signals: void connected(); void disconnected(); diff --git a/src/libs/ssh/sshconnectionmanager.cpp b/src/libs/ssh/sshconnectionmanager.cpp index 293ac6e9d2..04aa2effe1 100644 --- a/src/libs/ssh/sshconnectionmanager.cpp +++ b/src/libs/ssh/sshconnectionmanager.cpp @@ -97,6 +97,8 @@ public: continue; if (connection->thread() != QThread::currentThread()) { + if (connection->channelCount() != 0) + continue; QMetaObject::invokeMethod(this, "switchToCallerThread", Qt::BlockingQueuedConnection, Q_ARG(SshConnection *, connection), -- GitLab