Commit da647ad6 authored by Tobias Hunger's avatar Tobias Hunger
Browse files

ssh: Add option to force a new connection



Allow for users to force the ssh connection manager to reconnect
instead of re-using an existing connection.

This makes sure the connection is never handed out again for new
requests but keeps it functional for as long as it is still in use
elsewhere.

Change-Id: I9c816c4af380bc3a898bd5cc3669e7062d58b172
Reviewed-by: default avatarChristian Kandeler <christian.kandeler@nokia.com>
parent 8a2b9a48
......@@ -82,58 +82,99 @@ public:
m_cleanupTimer.start(5*60*1000);
}
ConnectionInfo::Ptr findConnection(const SshConnection::Ptr &connection)
QSharedPointer<SshConnection> acquireConnection(const SshConnectionParameters &sshParams)
{
foreach (const ConnectionInfo::Ptr &connInfo, m_connections) {
if (connInfo->connection == connection)
return connInfo;
QMutexLocker locker(&m_listMutex);
// Check in-use connections:
foreach (SshConnection::Ptr connection, m_acquiredConnections) {
if (connection->connectionParameters() != sshParams)
continue;
if (connection->thread() != QThread::currentThread())
break;
if (m_deprecatedConnections.contains(connection)) // we were asked to no longer use this one...
break;
m_acquiredConnections.append(connection);
return connection;
}
return ConnectionInfo::Ptr();
}
// Checked cached open connections:
foreach (SshConnection::Ptr connection, m_unacquiredConnections) {
if (connection->state() != SshConnection::Connected
|| connection->connectionParameters() != sshParams)
continue;
if (connection->thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "switchToCallerThread",
Qt::BlockingQueuedConnection,
Q_ARG(SshConnection *, connection.data()),
Q_ARG(QObject *, QThread::currentThread()));
}
QSharedPointer<SshConnection> acquireConnection(const SshConnectionParameters &sshParams)
m_unacquiredConnections.removeOne(connection);
m_acquiredConnections.append(connection);
return connection;
}
// create a new connection:
SshConnection::Ptr connection = SshConnection::create(sshParams);
connect(connection.data(), SIGNAL(disconnected()), this, SLOT(cleanup()));
m_acquiredConnections.append(connection);
return connection;
}
void releaseConnection(const SshConnection::Ptr &connection)
{
QMutexLocker locker(&m_listMutex);
foreach (const ConnectionInfo::Ptr &connInfo, m_connections) {
const SshConnection::Ptr connection = connInfo->connection;
bool connectionUsable = false;
if (connection->state() == SshConnection::Connected
&& connection->connectionParameters() == sshParams) {
if (connInfo->refCount == 0) {
if (connection->thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "switchToCallerThread",
Qt::BlockingQueuedConnection,
Q_ARG(SshConnection *, connection.data()),
Q_ARG(QObject *, QThread::currentThread()));
m_acquiredConnections.removeOne(connection);
if (!m_acquiredConnections.contains(connection)) {
// no longer in use:
connection->moveToThread(QCoreApplication::instance()->thread());
if (m_deprecatedConnections.contains(connection))
m_deprecatedConnections.removeAll(connection);
else if (connection->state() == SshConnection::Connected) {
// Make sure to only keep one connection open
bool haveConnection = false;
foreach (SshConnection::Ptr conn, m_unacquiredConnections) {
if (conn->connectionParameters() == connection->connectionParameters()) {
haveConnection = true;
break;
}
connectionUsable = true;
} else if (connection->thread() == QThread::currentThread()) {
connectionUsable = true;
}
if (connectionUsable) {
++connInfo->refCount;
return connection;
}
if (!haveConnection)
m_unacquiredConnections.append(connection);
}
}
ConnectionInfo::Ptr connInfo
= ConnectionInfo::create(SshConnection::create(sshParams));
m_connections << connInfo;
return connInfo->connection;
}
void releaseConnection(const SshConnection::Ptr &connection)
void forceNewConnection(const SshConnectionParameters &sshParams)
{
QMutexLocker locker(&m_listMutex);
ConnectionInfo::Ptr connInfo = findConnection(connection);
Q_ASSERT_X(connInfo, Q_FUNC_INFO, "Fatal: Unowned SSH Connection released.");
if (--connInfo->refCount == 0) {
connection->moveToThread(QCoreApplication::instance()->thread());
if (connection->state() != SshConnection::Connected)
m_connections.removeOne(connInfo);
SshConnection::Ptr toReset;
foreach (SshConnection::Ptr connection, m_unacquiredConnections) {
if (connection->connectionParameters() == sshParams) {
toReset = connection;
break;
}
}
if (toReset.isNull()) {
foreach (SshConnection::Ptr connection, m_acquiredConnections) {
if (connection->connectionParameters() == sshParams) {
toReset = connection;
break;
}
}
}
if (!toReset.isNull() && !m_deprecatedConnections.contains(toReset))
m_deprecatedConnections.append(toReset);
}
private:
......@@ -142,21 +183,25 @@ private:
connection->moveToThread(qobject_cast<QThread *>(threadObj));
}
Q_SLOT void cleanup()
private slots:
void cleanup()
{
QMutexLocker locker(&m_listMutex);
foreach (const ConnectionInfo::Ptr &connInfo, m_connections) {
if (connInfo->refCount == 0 &&
connInfo->connection->state() != SshConnection::Connected) {
m_connections.removeOne(connInfo);
}
}
SshConnection::Ptr connection(static_cast<SshConnection *>(sender()));
if (connection.isNull())
return;
m_unacquiredConnections.removeAll(connection);
}
private:
// We expect the number of concurrently open connections to be small.
// If that turns out to not be the case, we can still use a data
// structure with faster access.
QList<ConnectionInfo::Ptr> m_connections;
QList<SshConnection::Ptr> m_unacquiredConnections;
QList<SshConnection::Ptr> m_acquiredConnections;
QList<SshConnection::Ptr> m_deprecatedConnections;
QMutex m_listMutex;
QTimer m_cleanupTimer;
......@@ -191,6 +236,11 @@ void SshConnectionManager::releaseConnection(const SshConnection::Ptr &connectio
d->releaseConnection(connection);
}
void SshConnectionManager::forceNewConnection(const SshConnectionParameters &sshParams)
{
d->forceNewConnection(sshParams);
}
} // namespace Utils
#include "sshconnectionmanager.moc"
......@@ -51,6 +51,8 @@ public:
QSharedPointer<SshConnection> acquireConnection(const SshConnectionParameters &sshParams);
void releaseConnection(const QSharedPointer<SshConnection> &connection);
// Make sure the next acquireConnection with the given parameters will return a new connection.
void forceNewConnection(const SshConnectionParameters &sshParams);
private:
explicit SshConnectionManager();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment