Ssh: Rename SshConnectionParameters into SshParameters

Move it to its own header.
Get rid of SshConnection and SshConnectionManager,
as they are not used anymore.

Change-Id: I52fe20d7816ea57e7a7158ab2ae9565d50a76e21
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Jarek Kobus
2022-05-12 18:43:44 +02:00
parent 0a30445181
commit 87f3e7563c
45 changed files with 337 additions and 1193 deletions
+1 -7
View File
@@ -3,13 +3,7 @@ add_qtc_library(QtcSsh
SOURCES
ssh.qrc
ssh_global.h
sshconnection.cpp sshconnection.h
sshconnectionmanager.cpp sshconnectionmanager.h
sshkeycreationdialog.cpp sshkeycreationdialog.h sshkeycreationdialog.ui
sshlogging.cpp sshlogging_p.h
sshconnection.cpp sshconnection.h
sshconnectionmanager.cpp sshconnectionmanager.h
sshkeycreationdialog.cpp sshkeycreationdialog.h sshkeycreationdialog.ui
sshlogging.cpp sshlogging_p.h
sshparameters.cpp sshparameters.h
sshsettings.cpp sshsettings.h
)
+2 -6
View File
@@ -18,15 +18,11 @@ Project {
files: [
"ssh.qrc",
"sshconnection.h",
"sshconnection.cpp",
"sshconnectionmanager.cpp",
"sshconnectionmanager.h",
"sshkeycreationdialog.cpp",
"sshkeycreationdialog.h",
"sshkeycreationdialog.ui",
"sshlogging.cpp",
"sshlogging_p.h",
"sshparameters.cpp",
"sshparameters.h",
"sshsettings.cpp",
"sshsettings.h",
]
-435
View File
@@ -1,435 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "sshconnection.h"
#include "sshlogging_p.h"
#include "sshsettings.h"
#include <utils/environment.h>
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <QByteArrayList>
#include <QTemporaryDir>
#include <QTimer>
#include <memory>
/*!
\class QSsh::SshConnection
\brief The SshConnection class provides an SSH connection via an OpenSSH client
running in master mode.
It operates asynchronously (non-blocking) and is not thread-safe.
If connection sharing is turned off, the class operates as a simple factory
for processes etc and "connecting" always succeeds. The actual connection
is then established later, e.g. when starting the remote process.
*/
namespace QSsh {
using namespace Internal;
using namespace Utils;
SshConnectionParameters::SshConnectionParameters()
{
url.setPort(0);
}
QStringList SshConnectionParameters::connectionOptions(const FilePath &binary) const
{
QString hostKeyCheckingString;
switch (hostKeyCheckingMode) {
case SshHostKeyCheckingNone:
case SshHostKeyCheckingAllowNoMatch:
// There is "accept-new" as well, but only since 7.6.
hostKeyCheckingString = "no";
break;
case SshHostKeyCheckingStrict:
hostKeyCheckingString = "yes";
break;
}
QStringList args{"-o", "StrictHostKeyChecking=" + hostKeyCheckingString,
"-o", "Port=" + QString::number(port())};
if (!userName().isEmpty())
args.append({"-o", "User=" + userName()});
const bool keyOnly = authenticationType ==
SshConnectionParameters::AuthenticationTypeSpecificKey;
if (keyOnly) {
args << "-o" << "IdentitiesOnly=yes";
args << "-i" << privateKeyFile.path();
}
if (keyOnly || SshSettings::askpassFilePath().isEmpty())
args << "-o" << "BatchMode=yes";
bool useTimeout = timeout != 0;
if (useTimeout && HostOsInfo::isWindowsHost()
&& binary.toString().toLower().contains("/system32/")) {
useTimeout = false;
}
if (useTimeout)
args << "-o" << ("ConnectTimeout=" + QString::number(timeout));
return args;
}
bool SshConnectionParameters::setupSshEnvironment(QtcProcess *process)
{
Environment env = process->controlEnvironment();
if (env.size() == 0)
env = Environment::systemEnvironment();
const bool hasDisplay = env.hasKey("DISPLAY") && (env.value("DISPLAY") != QString(":0"));
if (SshSettings::askpassFilePath().exists()) {
env.set("SSH_ASKPASS", SshSettings::askpassFilePath().toUserOutput());
// OpenSSH only uses the askpass program if DISPLAY is set, regardless of the platform.
if (!env.hasKey("DISPLAY"))
env.set("DISPLAY", ":0");
}
process->setEnvironment(env);
// Otherwise, ssh will ignore SSH_ASKPASS and read from /dev/tty directly.
process->setDisableUnixTerminal();
return hasDisplay;
}
static inline bool equals(const SshConnectionParameters &p1, const SshConnectionParameters &p2)
{
return p1.url == p2.url
&& p1.authenticationType == p2.authenticationType
&& p1.privateKeyFile == p2.privateKeyFile
&& p1.hostKeyCheckingMode == p2.hostKeyCheckingMode
&& p1.x11DisplayName == p2.x11DisplayName
&& p1.timeout == p2.timeout;
}
bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2)
{
return equals(p1, p2);
}
bool operator!=(const SshConnectionParameters &p1, const SshConnectionParameters &p2)
{
return !equals(p1, p2);
}
struct SshConnection::SshConnectionPrivate
{
SshConnectionPrivate(const SshConnectionParameters &sshParameters)
: connParams(sshParameters)
{
SshConnectionParameters::setupSshEnvironment(&masterProcess);
}
QString fullProcessError()
{
QString error;
if (masterProcess.exitStatus() != QProcess::NormalExit)
error = masterProcess.errorString();
const QByteArray stdErr = masterProcess.readAllStandardError();
if (!stdErr.isEmpty()) {
if (!error.isEmpty())
error.append('\n');
error.append(QString::fromLocal8Bit(stdErr));
}
return error;
}
QString socketFilePath() const
{
QTC_ASSERT(masterSocketDir, return QString());
return masterSocketDir->path() + "/cs";
}
QStringList connectionOptions(const FilePath &binary) const
{
QStringList options = connParams.connectionOptions(binary);
if (sharingEnabled)
options << "-o" << ("ControlPath=" + socketFilePath());
return options;
}
QStringList connectionArgs(const FilePath &binary) const
{
return connectionOptions(binary) << connParams.host();
}
const SshConnectionParameters connParams;
QtcProcess masterProcess;
QString errorString;
std::unique_ptr<QTemporaryDir> masterSocketDir;
State state = Unconnected;
const bool sharingEnabled = SshSettings::connectionSharingEnabled();
};
SshConnection::SshConnection(const SshConnectionParameters &serverInfo, QObject *parent)
: QObject(parent), d(new SshConnectionPrivate(serverInfo))
{
connect(&d->masterProcess, &QtcProcess::readyReadStandardOutput, [this] {
const QByteArray reply = d->masterProcess.readAllStandardOutput();
if (reply == "\n")
emitConnected();
});
connect(&d->masterProcess, &QtcProcess::done, this, [this] {
if (d->masterProcess.error() == QProcess::FailedToStart) {
emitError(tr("Cannot establish SSH connection: Control process failed to start: %1")
.arg(d->fullProcessError()));
return;
}
if (d->state == Disconnecting) {
emitDisconnected();
return;
}
const QString procError = d->fullProcessError();
QString errorMsg = tr("SSH connection failure.");
if (!procError.isEmpty())
errorMsg.append('\n').append(procError);
emitError(errorMsg);
});
if (!d->connParams.x11DisplayName.isEmpty()) {
Environment env = d->masterProcess.environment();
env.set("DISPLAY", d->connParams.x11DisplayName);
d->masterProcess.setEnvironment(env);
}
}
void SshConnection::connectToHost()
{
d->state = Connecting;
QTimer::singleShot(0, this, &SshConnection::doConnectToHost);
}
void SshConnection::disconnectFromHost()
{
switch (d->state) {
case Connecting:
case Connected:
if (!d->sharingEnabled) {
QTimer::singleShot(0, this, &SshConnection::emitDisconnected);
return;
}
d->state = Disconnecting;
if (HostOsInfo::isWindowsHost())
d->masterProcess.kill();
else
d->masterProcess.terminate();
break;
case Unconnected:
case Disconnecting:
break;
}
}
SshConnection::State SshConnection::state() const
{
return d->state;
}
QString SshConnection::errorString() const
{
return d->errorString;
}
SshConnectionParameters SshConnection::connectionParameters() const
{
return d->connParams;
}
QStringList SshConnection::connectionOptions(const FilePath &binary) const
{
return d->connectionOptions(binary);
}
bool SshConnection::sharingEnabled() const
{
return d->sharingEnabled;
}
SshConnection::~SshConnection()
{
disconnect();
disconnectFromHost();
delete d;
}
void SshConnection::doConnectToHost()
{
if (d->state != Connecting)
return;
const FilePath sshBinary = SshSettings::sshFilePath();
if (!sshBinary.exists()) {
emitError(tr("Cannot establish SSH connection: ssh binary \"%1\" does not exist.")
.arg(sshBinary.toUserOutput()));
return;
}
if (!d->sharingEnabled) {
emitConnected();
return;
}
d->masterSocketDir.reset(new QTemporaryDir);
if (!d->masterSocketDir->isValid()) {
emitError(tr("Cannot establish SSH connection: Failed to create temporary "
"directory for control socket: %1")
.arg(d->masterSocketDir->errorString()));
return;
}
QStringList args = QStringList{"-M", "-N", "-o", "ControlPersist=no",
"-o", "PermitLocalCommand=yes", // Enable local command
"-o", "LocalCommand=echo"} // Local command is executed after successfully
// connecting to the server. "echo" will print "\n"
// on the process output if everything went fine.
<< d->connectionArgs(sshBinary);
if (!d->connParams.x11DisplayName.isEmpty())
args.prepend("-X");
qCDebug(sshLog) << "establishing connection:" << sshBinary.toUserOutput() << args;
d->masterProcess.setCommand(CommandLine(sshBinary, args));
d->masterProcess.start();
}
void SshConnection::emitError(const QString &reason)
{
const State oldState = d->state;
d->state = Unconnected;
d->errorString = reason;
emit errorOccurred();
if (oldState == Connected)
emitDisconnected();
}
void SshConnection::emitConnected()
{
d->state = Connected;
emit connected();
}
void SshConnection::emitDisconnected()
{
d->state = Unconnected;
emit disconnected();
}
#ifdef WITH_TESTS
namespace SshTest {
const QString getHostFromEnvironment()
{
const QString host = QString::fromLocal8Bit(qgetenv("QTC_SSH_TEST_HOST"));
if (host.isEmpty() && qEnvironmentVariableIsSet("QTC_SSH_TEST_DEFAULTS"))
return QString("127.0.0.1");
return host;
}
quint16 getPortFromEnvironment()
{
const int port = qEnvironmentVariableIntValue("QTC_SSH_TEST_PORT");
return port != 0 ? quint16(port) : 22;
}
const QString getUserFromEnvironment()
{
return QString::fromLocal8Bit(qgetenv("QTC_SSH_TEST_USER"));
}
const QString getKeyFileFromEnvironment()
{
const FilePath defaultKeyFile = FileUtils::homePath() / ".ssh/id_rsa";
const QString keyFile = QString::fromLocal8Bit(qgetenv("QTC_SSH_TEST_KEYFILE"));
if (keyFile.isEmpty()) {
if (qEnvironmentVariableIsSet("QTC_SSH_TEST_DEFAULTS"))
return defaultKeyFile.toString();
}
return keyFile;
}
const QString userAtHost()
{
QString userMidFix = getUserFromEnvironment();
if (!userMidFix.isEmpty())
userMidFix.append('@');
return userMidFix + getHostFromEnvironment();
}
SshConnectionParameters getParameters()
{
SshConnectionParameters params;
if (!qEnvironmentVariableIsSet("QTC_SSH_TEST_DEFAULTS")) {
params.setUserName(getUserFromEnvironment());
params.privateKeyFile = Utils::FilePath::fromUserInput(getKeyFileFromEnvironment());
}
params.setHost(getHostFromEnvironment());
params.setPort(getPortFromEnvironment());
params.timeout = 10;
params.authenticationType = !params.privateKeyFile.isEmpty()
? QSsh::SshConnectionParameters::AuthenticationTypeSpecificKey
: QSsh::SshConnectionParameters::AuthenticationTypeAll;
return params;
}
bool checkParameters(const QSsh::SshConnectionParameters &params)
{
if (qEnvironmentVariableIsSet("QTC_SSH_TEST_DEFAULTS"))
return true;
if (params.host().isEmpty()) {
qWarning("No hostname provided. Set QTC_SSH_TEST_HOST.");
return false;
}
if (params.userName().isEmpty())
qWarning("No user name provided - test may fail with empty default. Set QTC_SSH_TEST_USER.");
if (params.privateKeyFile.isEmpty()) {
qWarning("No key file provided. Set QTC_SSH_TEST_KEYFILE.");
return false;
}
return true;
}
void printSetupHelp()
{
qInfo() << "\n\n"
"In order to run this test properly it requires some setup (example for fedora):\n"
"1. Run a server on the host to connect to:\n"
" systemctl start sshd\n"
"2. Create your own ssh key (needed only once). For fedora it needs ecdsa type:\n"
" ssh-keygen -t ecdsa\n"
"3. Make your public key known to the server (needed only once):\n"
" ssh-copy-id -i [full path to your public key] [user@host]\n"
"4. Set the env variables before executing test:\n"
" QTC_SSH_TEST_HOST=127.0.0.1\n"
" QTC_SSH_TEST_KEYFILE=[full path to your private key]\n"
" QTC_SSH_TEST_USER=[your user name]\n";
}
} // namespace SshTest
#endif
} // namespace QSsh
-226
View File
@@ -1,226 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "sshconnectionmanager.h"
#include "sshconnection.h"
#include "sshsettings.h"
#include <utils/qtcassert.h>
#include <QCoreApplication>
#include <QHash>
#include <QObject>
#include <QThread>
#include <QTimer>
namespace QSsh {
namespace Internal {
class SshConnectionManagerPrivate : public QObject
{
public:
SshConnectionManagerPrivate()
{
connect(&m_removalTimer, &QTimer::timeout,
this, &SshConnectionManagerPrivate::removeInactiveConnections);
m_removalTimer.start(SshSettings::connectionSharingTimeout() * 1000 * 60 / 2);
}
~SshConnectionManagerPrivate() override
{
for (auto it = m_connections.cbegin(); it != m_connections.cend(); ++it) {
SshConnection * const connection = it.key();
const SshConnectionState &state = it.value();
QTC_CHECK(state.refCount() == 0);
QTC_CHECK(!state.isStale());
disconnect(connection, nullptr, this, nullptr);
delete connection;
}
}
SshConnection *acquireConnection(const SshConnectionParameters &sshParams)
{
if (SshSettings::connectionSharingEnabled()) {
for (auto it = m_connections.begin(); it != m_connections.end(); ++it) {
SshConnection * const connection = it.key();
if (connection->connectionParameters() != sshParams)
continue;
SshConnectionState &state = it.value();
if (state.isStale())
continue;
if (state.refCount() == 0 && connection->state() != SshConnection::Connected)
continue;
state.ref();
return connection;
}
}
SshConnection * const connection = new SshConnection(sshParams);
if (SshSettings::connectionSharingEnabled()) {
connect(connection, &SshConnection::disconnected,
this, [this, connection] { cleanup(connection); });
m_connections.insert(connection, {});
}
return connection;
}
void releaseConnection(SshConnection *connection)
{
auto it = m_connections.find(connection);
bool doDelete = false;
if (it == m_connections.end()) {
QTC_ASSERT(!connection->sharingEnabled(), return);
doDelete = true;
} else {
SshConnectionState &state = it.value();
if (state.deref())
return;
if (state.isStale() || connection->state() != SshConnection::Connected) {
doDelete = true;
m_connections.erase(it);
}
}
if (doDelete) {
disconnect(connection, nullptr, this, nullptr);
connection->deleteLater();
}
}
void forceNewConnection(const SshConnectionParameters &sshParams)
{
auto it = m_connections.begin();
while (it != m_connections.end()) {
SshConnection * const connection = it.key();
if (connection->connectionParameters() != sshParams) {
++it;
continue;
}
SshConnectionState &state = it.value();
if (state.refCount()) {
state.makeStale();
++it;
continue;
}
disconnect(connection, nullptr, this, nullptr);
delete connection;
it = m_connections.erase(it);
}
}
private:
void cleanup(SshConnection *connection)
{
auto it = m_connections.find(connection);
if (it == m_connections.end())
return;
SshConnectionState &state = it.value();
if (state.refCount())
return;
disconnect(connection, nullptr, this, nullptr);
connection->deleteLater();
m_connections.erase(it);
}
void removeInactiveConnections()
{
auto it = m_connections.begin();
while (it != m_connections.end()) {
SshConnection * const connection = it.key();
SshConnectionState &state = it.value();
if (state.refCount() == 0 && state.scheduleForRemoval()) {
disconnect(connection, nullptr, this, nullptr);
connection->deleteLater();
it = m_connections.erase(it);
} else {
++it;
}
}
}
private:
struct SshConnectionState {
void ref() { ++m_ref; m_scheduledForRemoval = false; }
bool deref() { QTC_ASSERT(m_ref, return false); return --m_ref; }
int refCount() const { return m_ref; }
void makeStale() { m_isStale = true; }
bool isStale() const { return m_isStale; }
bool scheduleForRemoval()
{
const bool ret = m_scheduledForRemoval;
m_scheduledForRemoval = true;
return ret;
}
private:
int m_ref = 1; // 0 means unacquired connection
bool m_isStale = false;
bool m_scheduledForRemoval = false;
};
QHash<SshConnection *, SshConnectionState> m_connections;
QTimer m_removalTimer;
};
} // namespace Internal
SshConnectionManager::SshConnectionManager()
: d(new Internal::SshConnectionManagerPrivate())
{
QTC_CHECK(QThread::currentThread() == qApp->thread());
}
SshConnectionManager::~SshConnectionManager()
{
delete d;
}
SshConnection *SshConnectionManager::acquireConnection(const SshConnectionParameters &sshParams)
{
return instance()->d->acquireConnection(sshParams);
}
void SshConnectionManager::releaseConnection(SshConnection *connection)
{
instance()->d->releaseConnection(connection);
}
void SshConnectionManager::forceNewConnection(const SshConnectionParameters &sshParams)
{
instance()->d->forceNewConnection(sshParams);
}
} // namespace QSsh
-58
View File
@@ -1,58 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "ssh_global.h"
#include <utils/launcherinterface.h>
#include <utils/singleton.h>
namespace QSsh {
class SshConnection;
class SshConnectionParameters;
namespace Internal { class SshConnectionManagerPrivate; }
class QSSH_EXPORT SshConnectionManager final
: public Utils::SingletonWithOptionalDependencies<SshConnectionManager,
Utils::LauncherInterface>
{
public:
static SshConnection *acquireConnection(const SshConnectionParameters &sshParams);
static void releaseConnection(SshConnection *connection);
// Make sure the next acquireConnection with the given parameters will return a new connection.
static void forceNewConnection(const SshConnectionParameters &sshParams);
private:
SshConnectionManager();
~SshConnectionManager();
Internal::SshConnectionManagerPrivate *d;
friend class Utils::SingletonWithOptionalDependencies<SshConnectionManager, Utils::LauncherInterface>;
};
} // namespace QSsh
-32
View File
@@ -1,32 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "sshlogging_p.h"
namespace QSsh {
namespace Internal {
Q_LOGGING_CATEGORY(sshLog, "qtc.ssh", QtWarningMsg)
} // namespace Internal
} // namespace QSsh
-34
View File
@@ -1,34 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QLoggingCategory>
namespace QSsh {
namespace Internal {
Q_DECLARE_LOGGING_CATEGORY(sshLog)
} // namespace Internal
} // namespace QSsh
+222
View File
@@ -0,0 +1,222 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "sshparameters.h"
#include "sshsettings.h"
#include <utils/environment.h>
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <QDebug>
#include <memory>
using namespace Utils;
namespace QSsh {
SshParameters::SshParameters()
{
url.setPort(0);
}
QStringList SshParameters::connectionOptions(const FilePath &binary) const
{
QString hostKeyCheckingString;
switch (hostKeyCheckingMode) {
case SshHostKeyCheckingNone:
case SshHostKeyCheckingAllowNoMatch:
// There is "accept-new" as well, but only since 7.6.
hostKeyCheckingString = "no";
break;
case SshHostKeyCheckingStrict:
hostKeyCheckingString = "yes";
break;
}
QStringList args{"-o", "StrictHostKeyChecking=" + hostKeyCheckingString,
"-o", "Port=" + QString::number(port())};
if (!userName().isEmpty())
args.append({"-o", "User=" + userName()});
const bool keyOnly = authenticationType ==
SshParameters::AuthenticationTypeSpecificKey;
if (keyOnly) {
args << "-o" << "IdentitiesOnly=yes";
args << "-i" << privateKeyFile.path();
}
if (keyOnly || SshSettings::askpassFilePath().isEmpty())
args << "-o" << "BatchMode=yes";
bool useTimeout = timeout != 0;
if (useTimeout && HostOsInfo::isWindowsHost()
&& binary.toString().toLower().contains("/system32/")) {
useTimeout = false;
}
if (useTimeout)
args << "-o" << ("ConnectTimeout=" + QString::number(timeout));
return args;
}
bool SshParameters::setupSshEnvironment(QtcProcess *process)
{
Environment env = process->controlEnvironment();
if (env.size() == 0)
env = Environment::systemEnvironment();
const bool hasDisplay = env.hasKey("DISPLAY") && (env.value("DISPLAY") != QString(":0"));
if (SshSettings::askpassFilePath().exists()) {
env.set("SSH_ASKPASS", SshSettings::askpassFilePath().toUserOutput());
// OpenSSH only uses the askpass program if DISPLAY is set, regardless of the platform.
if (!env.hasKey("DISPLAY"))
env.set("DISPLAY", ":0");
}
process->setEnvironment(env);
// Otherwise, ssh will ignore SSH_ASKPASS and read from /dev/tty directly.
process->setDisableUnixTerminal();
return hasDisplay;
}
static inline bool equals(const SshParameters &p1, const SshParameters &p2)
{
return p1.url == p2.url
&& p1.authenticationType == p2.authenticationType
&& p1.privateKeyFile == p2.privateKeyFile
&& p1.hostKeyCheckingMode == p2.hostKeyCheckingMode
&& p1.x11DisplayName == p2.x11DisplayName
&& p1.timeout == p2.timeout;
}
bool operator==(const SshParameters &p1, const SshParameters &p2)
{
return equals(p1, p2);
}
bool operator!=(const SshParameters &p1, const SshParameters &p2)
{
return !equals(p1, p2);
}
#ifdef WITH_TESTS
namespace SshTest {
const QString getHostFromEnvironment()
{
const QString host = QString::fromLocal8Bit(qgetenv("QTC_SSH_TEST_HOST"));
if (host.isEmpty() && qEnvironmentVariableIsSet("QTC_SSH_TEST_DEFAULTS"))
return QString("127.0.0.1");
return host;
}
quint16 getPortFromEnvironment()
{
const int port = qEnvironmentVariableIntValue("QTC_SSH_TEST_PORT");
return port != 0 ? quint16(port) : 22;
}
const QString getUserFromEnvironment()
{
return QString::fromLocal8Bit(qgetenv("QTC_SSH_TEST_USER"));
}
const QString getKeyFileFromEnvironment()
{
const FilePath defaultKeyFile = FileUtils::homePath() / ".ssh/id_rsa";
const QString keyFile = QString::fromLocal8Bit(qgetenv("QTC_SSH_TEST_KEYFILE"));
if (keyFile.isEmpty()) {
if (qEnvironmentVariableIsSet("QTC_SSH_TEST_DEFAULTS"))
return defaultKeyFile.toString();
}
return keyFile;
}
const QString userAtHost()
{
QString userMidFix = getUserFromEnvironment();
if (!userMidFix.isEmpty())
userMidFix.append('@');
return userMidFix + getHostFromEnvironment();
}
SshParameters getParameters()
{
SshParameters params;
if (!qEnvironmentVariableIsSet("QTC_SSH_TEST_DEFAULTS")) {
params.setUserName(getUserFromEnvironment());
params.privateKeyFile = FilePath::fromUserInput(getKeyFileFromEnvironment());
}
params.setHost(getHostFromEnvironment());
params.setPort(getPortFromEnvironment());
params.timeout = 10;
params.authenticationType = !params.privateKeyFile.isEmpty()
? QSsh::SshParameters::AuthenticationTypeSpecificKey
: QSsh::SshParameters::AuthenticationTypeAll;
return params;
}
bool checkParameters(const QSsh::SshParameters &params)
{
if (qEnvironmentVariableIsSet("QTC_SSH_TEST_DEFAULTS"))
return true;
if (params.host().isEmpty()) {
qWarning("No hostname provided. Set QTC_SSH_TEST_HOST.");
return false;
}
if (params.userName().isEmpty())
qWarning("No user name provided - test may fail with empty default. Set QTC_SSH_TEST_USER.");
if (params.privateKeyFile.isEmpty()) {
qWarning("No key file provided. Set QTC_SSH_TEST_KEYFILE.");
return false;
}
return true;
}
void printSetupHelp()
{
qInfo() << "\n\n"
"In order to run this test properly it requires some setup (example for fedora):\n"
"1. Run a server on the host to connect to:\n"
" systemctl start sshd\n"
"2. Create your own ssh key (needed only once). For fedora it needs ecdsa type:\n"
" ssh-keygen -t ecdsa\n"
"3. Make your public key known to the server (needed only once):\n"
" ssh-copy-id -i [full path to your public key] [user@host]\n"
"4. Set the env variables before executing test:\n"
" QTC_SSH_TEST_HOST=127.0.0.1\n"
" QTC_SSH_TEST_KEYFILE=[full path to your private key]\n"
" QTC_SSH_TEST_USER=[your user name]\n";
}
} // namespace SshTest
#endif
} // namespace QSsh
@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -29,14 +29,8 @@
#include <utils/filepath.h>
#include <QFlags>
#include <QHostAddress>
#include <QObject>
#include <QString>
#include <QUrl>
#include <memory>
namespace Utils { class QtcProcess; }
namespace QSsh {
@@ -47,7 +41,7 @@ enum SshHostKeyCheckingMode {
SshHostKeyCheckingAllowNoMatch,
};
class QSSH_EXPORT SshConnectionParameters
class QSSH_EXPORT SshParameters
{
public:
enum AuthenticationType {
@@ -55,7 +49,7 @@ public:
AuthenticationTypeSpecificKey,
};
SshConnectionParameters();
SshParameters();
QString host() const { return url.host(); }
quint16 port() const { return url.port(); }
@@ -77,41 +71,8 @@ public:
static bool setupSshEnvironment(Utils::QtcProcess *process);
};
QSSH_EXPORT bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2);
QSSH_EXPORT bool operator!=(const SshConnectionParameters &p1, const SshConnectionParameters &p2);
class QSSH_EXPORT SshConnection : public QObject
{
Q_OBJECT
public:
enum State { Unconnected, Connecting, Connected, Disconnecting };
explicit SshConnection(const SshConnectionParameters &serverInfo, QObject *parent = nullptr);
void connectToHost();
void disconnectFromHost();
State state() const;
QString errorString() const;
SshConnectionParameters connectionParameters() const;
QStringList connectionOptions(const Utils::FilePath &binary) const;
bool sharingEnabled() const;
~SshConnection();
signals:
void connected();
void disconnected();
void errorOccurred();
private:
void doConnectToHost();
void emitError(const QString &reason);
void emitConnected();
void emitDisconnected();
struct SshConnectionPrivate;
SshConnectionPrivate * const d;
};
QSSH_EXPORT bool operator==(const SshParameters &p1, const SshParameters &p2);
QSSH_EXPORT bool operator!=(const SshParameters &p1, const SshParameters &p2);
#ifdef WITH_TESTS
namespace SshTest {
@@ -120,12 +81,12 @@ quint16 QSSH_EXPORT getPortFromEnvironment();
const QString QSSH_EXPORT getUserFromEnvironment();
const QString QSSH_EXPORT getKeyFileFromEnvironment();
const QSSH_EXPORT QString userAtHost();
SshConnectionParameters QSSH_EXPORT getParameters();
bool QSSH_EXPORT checkParameters(const SshConnectionParameters &params);
SshParameters QSSH_EXPORT getParameters();
bool QSSH_EXPORT checkParameters(const SshParameters &params);
void QSSH_EXPORT printSetupHelp();
} // namespace SshTest
#endif
} // namespace QSsh
Q_DECLARE_METATYPE(QSsh::SshConnectionParameters::AuthenticationType)
Q_DECLARE_METATYPE(QSsh::SshParameters::AuthenticationType)
+2 -2
View File
@@ -63,8 +63,8 @@ SingletonStaticData &Singleton::staticData(std::type_index index)
// Note: it's caller responsibility to ensure that this function is being called when all other
// threads don't use any singleton. As a good practice: finish all other threads that were using
// singletons before this function is called.
// Some singletons (currently e.g. SshConnectionManager) can work only in main thread,
// so this method should be called from main thread only.
// Some singletons may work only in main thread, so this method should be called from main thread
// only.
void Singleton::deleteAll()
{
QTC_ASSERT(QThread::currentThread() == qApp->thread(), return);
@@ -35,8 +35,6 @@
#include <utils/qtcassert.h>
#include <utils/pathchooser.h>
#include <ssh/sshconnection.h>
#include <QComboBox>
#include <QFormLayout>
#include <QLineEdit>
+4 -3
View File
@@ -36,7 +36,7 @@
#include <remotelinux/linuxprocessinterface.h>
#include <ssh/sshconnection.h>
#include <ssh/sshparameters.h>
#include <utils/portlist.h>
#include <utils/qtcassert.h>
@@ -48,6 +48,7 @@
#include <QWizard>
using namespace ProjectExplorer;
using namespace QSsh;
using namespace RemoteLinux;
using namespace Utils;
@@ -178,12 +179,12 @@ void QdbDevice::setupDefaultNetworkSettings(const QString &host)
{
setFreePorts(Utils::PortList::fromString("10000-10100"));
QSsh::SshConnectionParameters parameters = sshParameters();
SshParameters parameters = sshParameters();
parameters.setHost(host);
parameters.setUserName("root");
parameters.setPort(22);
parameters.timeout = 10;
parameters.authenticationType = QSsh::SshConnectionParameters::AuthenticationTypeAll;
parameters.authenticationType = SshParameters::AuthenticationTypeAll;
setSshParameters(parameters);
}
@@ -31,8 +31,6 @@
#include <debugger/debuggerruncontrol.h>
#include <ssh/sshconnection.h>
#include <utils/algorithm.h>
#include <utils/qtcprocess.h>
#include <utils/url.h>
@@ -26,11 +26,13 @@
#include "startremotedialog.h"
#include <coreplugin/icore.h>
#include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/kitchooser.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/runcontrol.h>
#include <ssh/sshconnection.h>
#include <ssh/sshparameters.h>
#include <QDialogButtonBox>
#include <QFormLayout>
+8 -6
View File
@@ -25,20 +25,22 @@
#include "debuggerdialogs.h"
#include "cdb/cdbengine.h"
#include "debuggerkitinformation.h"
#include "debuggerruncontrol.h"
#include "cdb/cdbengine.h"
#include <app/app_version.h>
#include <coreplugin/icore.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/toolchain.h>
#include <app/app_version.h>
#include <utils/pathchooser.h>
#include <utils/fancylineedit.h>
#include <utils/qtcassert.h>
#include <ssh/sshparameters.h>
#include <ssh/sshconnection.h>
#include <utils/fancylineedit.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <QButtonGroup>
#include <QCheckBox>
+4 -2
View File
@@ -101,7 +101,8 @@
#include <projectexplorer/target.h>
#include <projectexplorer/taskhub.h>
#include <projectexplorer/toolchain.h>
#include <ssh/sshconnection.h>
#include <ssh/sshparameters.h>
#include <texteditor/texteditor.h>
#include <texteditor/textdocument.h>
@@ -377,6 +378,7 @@ using namespace Debugger::Constants;
using namespace Debugger::Internal;
using namespace ExtensionSystem;
using namespace ProjectExplorer;
using namespace QSsh;
using namespace TextEditor;
using namespace Utils;
@@ -1835,7 +1837,7 @@ void DebuggerPluginPrivate::attachToQmlPort()
qmlServer.setPort(dlg.port());
debugger->setQmlServer(qmlServer);
QSsh::SshConnectionParameters sshParameters = device->sshParameters();
SshParameters sshParameters = device->sshParameters();
debugger->setRemoteChannel(sshParameters.host(), sshParameters.port());
debugger->setStartMode(AttachToQmlServer);
@@ -73,8 +73,6 @@
#include <qtsupport/qtkitinformation.h>
#include <ssh/sshconnection.h>
#include <QTcpServer>
#include <QTimer>
@@ -35,7 +35,6 @@
#include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/target.h>
#include <ssh/sshconnection.h>
#include <utils/qtcprocess.h>
#include <QAction>
@@ -33,8 +33,6 @@
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/runcontrol.h>
#include <ssh/sshconnection.h>
#include <utils/environment.h>
#include <utils/hostosinfo.h>
#include <utils/portlist.h>
@@ -69,4 +69,4 @@ private:
Internal::DeviceFileSystemModelPrivate * const d;
};
} // namespace QSsh;
} // namespace ProjectExplorer;
@@ -25,16 +25,14 @@
#include "deviceusedportsgatherer.h"
#include <ssh/sshconnection.h>
#include <projectexplorer/devicesupport/idevice.h>
#include <ssh/sshparameters.h>
#include <utils/port.h>
#include <utils/portlist.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/url.h>
using namespace QSsh;
using namespace Utils;
namespace ProjectExplorer {
@@ -34,7 +34,7 @@
#include "../runconfiguration.h"
#include <coreplugin/icore.h>
#include <ssh/sshconnection.h>
#include <ssh/sshparameters.h>
#include <utils/displayname.h>
#include <utils/icon.h>
#include <utils/portlist.h>
@@ -100,6 +100,7 @@
* Creates an identical copy of a device object.
*/
using namespace QSsh;
using namespace Utils;
namespace ProjectExplorer {
@@ -130,8 +131,8 @@ const char HostKeyCheckingKey[] = "HostKeyChecking";
const char DebugServerKey[] = "DebugServerKey";
const char QmlRuntimeKey[] = "QmlsceneKey";
using AuthType = QSsh::SshConnectionParameters::AuthenticationType;
const AuthType DefaultAuthType = QSsh::SshConnectionParameters::AuthenticationTypeAll;
using AuthType = SshParameters::AuthenticationType;
const AuthType DefaultAuthType = SshParameters::AuthenticationTypeAll;
const IDevice::MachineType DefaultMachineType = IDevice::Hardware;
const int DefaultTimeout = 10;
@@ -153,7 +154,7 @@ public:
int version = 0; // This is used by devices that have been added by the SDK.
QReadWriteLock lock; // Currently used to protect sshParameters only
QSsh::SshConnectionParameters sshParameters;
SshParameters sshParameters;
PortList freePorts;
FilePath debugServerPath;
FilePath debugDumperPath = Core::ICore::resourcePath("debugger/");
@@ -633,16 +634,16 @@ void IDevice::fromMap(const QVariantMap &map)
// Pre-4.9, the authentication enum used to have more values
const int storedAuthType = map.value(QLatin1String(AuthKey), DefaultAuthType).toInt();
const bool outdatedAuthType = storedAuthType
> QSsh::SshConnectionParameters::AuthenticationTypeSpecificKey;
> SshParameters::AuthenticationTypeSpecificKey;
d->sshParameters.authenticationType = outdatedAuthType
? QSsh::SshConnectionParameters::AuthenticationTypeAll
? SshParameters::AuthenticationTypeAll
: static_cast<AuthType>(storedAuthType);
d->sshParameters.privateKeyFile =
FilePath::fromVariant(map.value(QLatin1String(KeyFileKey), defaultPrivateKeyFilePath()));
d->sshParameters.timeout = map.value(QLatin1String(TimeoutKey), DefaultTimeout).toInt();
d->sshParameters.hostKeyCheckingMode = static_cast<QSsh::SshHostKeyCheckingMode>
(map.value(QLatin1String(HostKeyCheckingKey), QSsh::SshHostKeyCheckingNone).toInt());
d->sshParameters.hostKeyCheckingMode = static_cast<SshHostKeyCheckingMode>
(map.value(QLatin1String(HostKeyCheckingKey), SshHostKeyCheckingNone).toInt());
QString portsSpec = map.value(PortsSpecKey).toString();
if (portsSpec.isEmpty())
@@ -719,13 +720,13 @@ QString IDevice::deviceStateToString() const
}
}
QSsh::SshConnectionParameters IDevice::sshParameters() const
SshParameters IDevice::sshParameters() const
{
QReadLocker locker(&d->lock);
return d->sshParameters;
}
void IDevice::setSshParameters(const QSsh::SshConnectionParameters &sshParameters)
void IDevice::setSshParameters(const SshParameters &sshParameters)
{
QWriteLocker locker(&d->lock);
d->sshParameters = sshParameters;
@@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE
class QWidget;
QT_END_NAMESPACE
namespace QSsh { class SshConnectionParameters; }
namespace QSsh { class SshParameters; }
namespace Utils {
class CommandLine;
@@ -192,8 +192,8 @@ public:
static QString defaultPrivateKeyFilePath();
static QString defaultPublicKeyFilePath();
QSsh::SshConnectionParameters sshParameters() const;
void setSshParameters(const QSsh::SshConnectionParameters &sshParameters);
QSsh::SshParameters sshParameters() const;
void setSshParameters(const QSsh::SshParameters &sshParameters);
enum ControlChannelHint { QmlControlChannel };
virtual QUrl toolControlChannel(const ControlChannelHint &) const;
@@ -30,7 +30,6 @@
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
using namespace QSsh;
using namespace Utils;
namespace ProjectExplorer {
@@ -37,7 +37,7 @@
#include <docker/dockerconstants.h>
#include <ssh/sshconnection.h>
#include <ssh/sshparameters.h>
#include <utils/algorithm.h>
#include <utils/elidinglabel.h>
@@ -131,7 +131,6 @@
#include <coreplugin/vcsmanager.h>
#include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginspec.h>
#include <ssh/sshconnection.h>
#include <ssh/sshsettings.h>
#include <texteditor/findinfiles.h>
#include <texteditor/textdocument.h>
@@ -190,6 +189,7 @@
using namespace Core;
using namespace ProjectExplorer::Internal;
using namespace QSsh;
using namespace Utils;
namespace ProjectExplorer {
@@ -2252,7 +2252,7 @@ void ProjectExplorerPlugin::extensionsInitialized()
TaskHub::addCategory(Constants::TASK_CATEGORY_SANITIZER,
tr("Sanitizer", "Category for sanitizer issues listed under 'Issues'"));
QSsh::SshSettings::loadSettings(Core::ICore::settings());
SshSettings::loadSettings(Core::ICore::settings());
const auto searchPathRetriever = [] {
FilePaths searchPaths = {Core::ICore::libexecPath()};
if (HostOsInfo::isWindowsHost()) {
@@ -2271,7 +2271,7 @@ void ProjectExplorerPlugin::extensionsInitialized()
}
return searchPaths;
};
QSsh::SshSettings::setExtraSearchPathRetriever(searchPathRetriever);
SshSettings::setExtraSearchPathRetriever(searchPathRetriever);
const auto parseIssuesAction = new QAction(tr("Parse Build Output..."), this);
ActionContainer *mtools = ActionManager::actionContainer(Core::Constants::M_TOOLS);
+3 -2
View File
@@ -71,8 +71,9 @@
#include "journaldwatcher.h"
#endif
using namespace Utils;
using namespace ProjectExplorer::Internal;
using namespace QSsh;
using namespace Utils;
namespace {
static Q_LOGGING_CATEGORY(statesLog, "qtc.projectmanager.states", QtWarningMsg)
@@ -1119,7 +1120,7 @@ bool RunControl::showPromptToStopDialog(const QString &title,
void RunControl::provideAskPassEntry(Environment &env)
{
if (env.value("SUDO_ASKPASS").isEmpty()) {
const FilePath askpass = QSsh::SshSettings::askpassFilePath();
const FilePath askpass = SshSettings::askpassFilePath();
if (askpass.exists())
env.set("SUDO_ASKPASS", askpass.toUserOutput());
}
+3 -1
View File
@@ -28,9 +28,11 @@
#include "qnxconstants.h"
#include <remotelinux/genericlinuxdeviceconfigurationwizardpages.h>
#include <ssh/sshparameters.h>
#include <utils/portlist.h>
using namespace ProjectExplorer;
using namespace QSsh;
namespace Qnx {
namespace Internal {
@@ -49,7 +51,7 @@ QnxDeviceWizard::QnxDeviceWizard(QWidget *parent) :
setPage(KeyDeploymenPageId, m_keyDeploymentPage);
setPage(FinalPageId, m_finalPage);
m_finalPage->setCommitPage(true);
QSsh::SshConnectionParameters sshParams;
SshParameters sshParams;
sshParams.timeout = 10;
m_device = QnxDevice::create();
m_device->setupId(IDevice::ManuallyAdded);
@@ -29,15 +29,12 @@
#include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/target.h>
#include <ssh/sshconnection.h>
#include <ssh/sshconnectionmanager.h>
#include <ssh/sshparameters.h>
#include <QDateTime>
using namespace ProjectExplorer;
using namespace Utils;
using namespace QSsh;
namespace RemoteLinux {
@@ -29,7 +29,7 @@
#include "linuxdevice.h"
#include <projectexplorer/devicesupport/devicemanager.h>
#include <ssh/sshconnection.h>
#include <ssh/sshparameters.h>
#include <utils/filepath.h>
#include <utils/processinterface.h>
@@ -40,6 +40,7 @@
#include <QTimer>
using namespace ProjectExplorer;
using namespace QSsh;
using namespace Utils;
namespace RemoteLinux {
@@ -49,7 +50,7 @@ static const char TEST_DIR[] = "/tmp/testdir";
static const FilePath baseFilePath()
{
return FilePath::fromString("ssh://" + QSsh::SshTest::userAtHost() + QString(TEST_DIR));
return FilePath::fromString("ssh://" + SshTest::userAtHost() + QString(TEST_DIR));
}
TestLinuxDeviceFactory::TestLinuxDeviceFactory()
@@ -63,7 +64,7 @@ TestLinuxDeviceFactory::TestLinuxDeviceFactory()
device->setupId(IDevice::ManuallyAdded);
device->setType("test");
qDebug() << "device : " << device->type();
device->setSshParameters(QSsh::SshTest::getParameters());
device->setSshParameters(SshTest::getParameters());
return device;
});
}
@@ -71,22 +72,22 @@ TestLinuxDeviceFactory::TestLinuxDeviceFactory()
FilePath createFile(const QString &name)
{
FilePath testFilePath = baseFilePath() / name;
FilePath dummyFilePath = FilePath::fromString("ssh://" + QSsh::SshTest::userAtHost() + "/dev/null");
FilePath dummyFilePath = FilePath::fromString("ssh://" + SshTest::userAtHost() + "/dev/null");
dummyFilePath.copyFile(testFilePath);
return testFilePath;
}
void FileSystemAccessTest::initTestCase()
{
const QSsh::SshConnectionParameters params = QSsh::SshTest::getParameters();
const SshParameters params = SshTest::getParameters();
qDebug() << "Using following SSH parameter:"
<< "\nHost:" << params.host()
<< "\nPort:" << params.port()
<< "\nUser:" << params.userName()
<< "\nSSHKey:" << params.privateKeyFile;
if (!QSsh::SshTest::checkParameters(params)) {
if (!SshTest::checkParameters(params)) {
m_skippedAtWhole = true;
QSsh::SshTest::printSetupHelp();
SshTest::printSetupHelp();
QSKIP("Ensure you have added your default ssh public key to your own authorized keys and "
"environment QTC_REMOTELINUX_SSH_DEFAULTS set or follow setup help above.");
return;
@@ -181,7 +182,7 @@ void FileSystemAccessTest::testDirStatus()
void FileSystemAccessTest::testBytesAvailable()
{
FilePath testFilePath = FilePath::fromString("ssh://" + QSsh::SshTest::userAtHost() + "/tmp");
FilePath testFilePath = FilePath::fromString("ssh://" + SshTest::userAtHost() + "/tmp");
QVERIFY(testFilePath.exists());
QVERIFY(testFilePath.bytesAvailable() > 0);
}
@@ -43,7 +43,6 @@
#include <QString>
using namespace ProjectExplorer;
using namespace QSsh;
using namespace Utils;
namespace RemoteLinux {
@@ -31,7 +31,7 @@
#include <utils/portlist.h>
#include <utils/fancylineedit.h>
#include <utils/utilsicons.h>
#include <ssh/sshconnection.h>
#include <ssh/sshparameters.h>
#include <ssh/sshkeycreationdialog.h>
using namespace ProjectExplorer;
@@ -83,11 +83,11 @@ GenericLinuxDeviceConfigurationWidget::~GenericLinuxDeviceConfigurationWidget()
void GenericLinuxDeviceConfigurationWidget::authenticationTypeChanged()
{
SshConnectionParameters sshParams = device()->sshParameters();
SshParameters sshParams = device()->sshParameters();
const bool useKeyFile = m_ui->keyButton->isChecked();
sshParams.authenticationType = useKeyFile
? SshConnectionParameters::AuthenticationTypeSpecificKey
: SshConnectionParameters::AuthenticationTypeAll;
? SshParameters::AuthenticationTypeSpecificKey
: SshParameters::AuthenticationTypeAll;
device()->setSshParameters(sshParams);
m_ui->keyFileLineEdit->setEnabled(useKeyFile);
m_ui->keyLabel->setEnabled(useKeyFile);
@@ -95,35 +95,35 @@ void GenericLinuxDeviceConfigurationWidget::authenticationTypeChanged()
void GenericLinuxDeviceConfigurationWidget::hostNameEditingFinished()
{
SshConnectionParameters sshParams = device()->sshParameters();
SshParameters sshParams = device()->sshParameters();
sshParams.setHost(m_ui->hostLineEdit->text().trimmed());
device()->setSshParameters(sshParams);
}
void GenericLinuxDeviceConfigurationWidget::sshPortEditingFinished()
{
SshConnectionParameters sshParams = device()->sshParameters();
SshParameters sshParams = device()->sshParameters();
sshParams.setPort(m_ui->sshPortSpinBox->value());
device()->setSshParameters(sshParams);
}
void GenericLinuxDeviceConfigurationWidget::timeoutEditingFinished()
{
SshConnectionParameters sshParams = device()->sshParameters();
SshParameters sshParams = device()->sshParameters();
sshParams.timeout = m_ui->timeoutSpinBox->value();
device()->setSshParameters(sshParams);
}
void GenericLinuxDeviceConfigurationWidget::userNameEditingFinished()
{
SshConnectionParameters sshParams = device()->sshParameters();
SshParameters sshParams = device()->sshParameters();
sshParams.setUserName(m_ui->userLineEdit->text());
device()->setSshParameters(sshParams);
}
void GenericLinuxDeviceConfigurationWidget::keyFileEditingFinished()
{
SshConnectionParameters sshParams = device()->sshParameters();
SshParameters sshParams = device()->sshParameters();
sshParams.privateKeyFile = m_ui->keyFileLineEdit->filePath();
device()->setSshParameters(sshParams);
}
@@ -154,7 +154,7 @@ void GenericLinuxDeviceConfigurationWidget::createNewKey()
void GenericLinuxDeviceConfigurationWidget::hostKeyCheckingChanged(bool doCheck)
{
SshConnectionParameters sshParams = device()->sshParameters();
SshParameters sshParams = device()->sshParameters();
sshParams.hostKeyCheckingMode
= doCheck ? SshHostKeyCheckingAllowNoMatch : SshHostKeyCheckingNone;
device()->setSshParameters(sshParams);
@@ -192,13 +192,13 @@ void GenericLinuxDeviceConfigurationWidget::initGui()
= new QRegularExpressionValidator(QRegularExpression(PortList::regularExpression()), this);
m_ui->portsLineEdit->setValidator(portsValidator);
const SshConnectionParameters &sshParams = device()->sshParameters();
const SshParameters &sshParams = device()->sshParameters();
switch (sshParams.authenticationType) {
case SshConnectionParameters::AuthenticationTypeSpecificKey:
case SshParameters::AuthenticationTypeSpecificKey:
m_ui->keyButton->setChecked(true);
break;
case SshConnectionParameters::AuthenticationTypeAll:
case SshParameters::AuthenticationTypeAll:
m_ui->defaultAuthButton->setChecked(true);
break;
}
@@ -30,6 +30,7 @@
#include "remotelinux_constants.h"
#include <projectexplorer/devicesupport/idevice.h>
#include <ssh/sshparameters.h>
#include <utils/portlist.h>
#include <utils/fileutils.h>
@@ -69,7 +70,7 @@ GenericLinuxDeviceConfigurationWizard::GenericLinuxDeviceConfigurationWizard(QWi
d->device->setType(Constants::GenericLinuxOsType);
d->device->setMachineType(IDevice::Hardware);
d->device->setFreePorts(Utils::PortList::fromString(QLatin1String("10000-10100")));
SshConnectionParameters sshParams;
SshParameters sshParams;
sshParams.timeout = 10;
d->device->setSshParameters(sshParams);
d->setupPage.setDevice(d->device);
@@ -30,8 +30,9 @@
#include <projectexplorer/devicesupport/idevice.h>
#include <ssh/sshkeycreationdialog.h>
#include <utils/utilsicons.h>
#include <ssh/sshparameters.h>
#include <utils/pathchooser.h>
#include <utils/utilsicons.h>
#include <QHBoxLayout>
#include <QLabel>
@@ -39,6 +40,9 @@
#include <QStringList>
#include <QVBoxLayout>
using namespace QSsh;
using namespace Utils;
namespace RemoteLinux {
namespace Internal {
@@ -57,9 +61,6 @@ public:
} // namespace Internal
using namespace QSsh;
using namespace Utils;
GenericLinuxDeviceConfigurationWizardSetupPage::GenericLinuxDeviceConfigurationWizardSetupPage(
QWidget *parent) :
QWizardPage(parent), d(new Internal::GenericLinuxDeviceConfigurationWizardSetupPagePrivate)
@@ -94,7 +95,7 @@ bool GenericLinuxDeviceConfigurationWizardSetupPage::isComplete() const
bool GenericLinuxDeviceConfigurationWizardSetupPage::validatePage()
{
d->device->setDisplayName(configurationName());
SshConnectionParameters sshParams = d->device->sshParameters();
SshParameters sshParams = d->device->sshParameters();
sshParams.url = url();
d->device->setSshParameters(sshParams);
return true;
@@ -232,8 +233,8 @@ bool GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::isComplete() const
bool GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::validatePage()
{
if (!d->defaultKeys().contains(d->keyFileChooser.filePath())) {
SshConnectionParameters sshParams = d->device->sshParameters();
sshParams.authenticationType = SshConnectionParameters::AuthenticationTypeSpecificKey;
SshParameters sshParams = d->device->sshParameters();
sshParams.authenticationType = SshParameters::AuthenticationTypeSpecificKey;
sshParams.privateKeyFile = d->keyFileChooser.filePath();
d->device->setSshParameters(sshParams);
}
@@ -28,8 +28,6 @@
#include "linuxdevice.h"
#include "remotelinux_export.h"
#include <ssh/sshconnection.h>
#include <QWizardPage>
namespace RemoteLinux {
+23 -23
View File
@@ -42,7 +42,7 @@
#include <projectexplorer/devicesupport/sshdeviceprocesslist.h>
#include <projectexplorer/runcontrol.h>
#include <ssh/sshconnection.h>
#include <ssh/sshparameters.h>
#include <ssh/sshsettings.h>
#include <utils/algorithm.h>
@@ -86,10 +86,10 @@ class SshSharedConnection : public QObject
Q_OBJECT
public:
explicit SshSharedConnection(const SshConnectionParameters &sshParameters, QObject *parent = nullptr);
explicit SshSharedConnection(const SshParameters &sshParameters, QObject *parent = nullptr);
~SshSharedConnection() override;
SshConnectionParameters sshParameters() const { return m_sshParameters; }
SshParameters sshParameters() const { return m_sshParameters; }
void ref();
void deref();
void makeStale();
@@ -122,7 +122,7 @@ private:
QStringList connectionArgs(const FilePath &binary) const
{ return connectionOptions(binary) << m_sshParameters.host(); }
const SshConnectionParameters m_sshParameters;
const SshParameters m_sshParameters;
std::unique_ptr<QtcProcess> m_masterProcess;
std::unique_ptr<QTemporaryDir> m_masterSocketDir;
QTimer m_timer;
@@ -131,7 +131,7 @@ private:
QProcess::ProcessState m_state = QProcess::NotRunning;
};
SshSharedConnection::SshSharedConnection(const SshConnectionParameters &sshParameters, QObject *parent)
SshSharedConnection::SshSharedConnection(const SshParameters &sshParameters, QObject *parent)
: QObject(parent), m_sshParameters(sshParameters)
{
}
@@ -189,7 +189,7 @@ void SshSharedConnection::connectToHost()
}
m_masterProcess.reset(new QtcProcess);
SshConnectionParameters::setupSshEnvironment(m_masterProcess.get());
SshParameters::setupSshEnvironment(m_masterProcess.get());
m_timer.setSingleShot(true);
connect(&m_timer, &QTimer::timeout, this, &SshSharedConnection::autoDestructRequested);
connect(m_masterProcess.get(), &QtcProcess::readyReadStandardOutput, [this] {
@@ -383,7 +383,7 @@ public:
QByteArray outputForRunInShell(const QString &cmd);
QByteArray outputForRunInShell(const CommandLine &cmd);
void attachToSharedConnection(SshConnectionHandle *connectionHandle,
const SshConnectionParameters &sshParameters);
const SshParameters &sshParameters);
LinuxDevice *q = nullptr;
QThread m_shellThread;
@@ -426,7 +426,7 @@ public:
LinuxDevicePrivate *m_devicePrivate = nullptr;
QString m_socketFilePath;
SshConnectionParameters m_sshParameters;
SshParameters m_sshParameters;
bool m_connecting = false;
bool m_killed = false;
@@ -720,7 +720,7 @@ void SshProcessInterfacePrivate::doStart()
m_process.setTerminalMode(q->m_setup.m_terminalMode);
m_process.setWriteData(q->m_setup.m_writeData);
// TODO: what about other fields from m_setup?
SshConnectionParameters::setupSshEnvironment(&m_process);
SshParameters::setupSshEnvironment(&m_process);
if (!m_sshParameters.x11DisplayName.isEmpty()) {
Environment env = m_process.controlEnvironment();
// Note: it seems this is no-op when shared connection is used.
@@ -760,9 +760,9 @@ CommandLine SshProcessInterfacePrivate::fullLocalCommandLine() const
// ShellThreadHandler
static SshConnectionParameters displayless(const SshConnectionParameters &sshParameters)
static SshParameters displayless(const SshParameters &sshParameters)
{
SshConnectionParameters parameters = sshParameters;
SshParameters parameters = sshParameters;
parameters.x11DisplayName.clear();
return parameters;
}
@@ -786,13 +786,13 @@ public:
}
// Call me with shell mutex locked
bool start(const SshConnectionParameters &parameters)
bool start(const SshParameters &parameters)
{
closeShell();
setSshParameters(parameters);
m_shell.reset(new QtcProcess);
SshConnectionParameters::setupSshEnvironment(m_shell.get());
SshParameters::setupSshEnvironment(m_shell.get());
const FilePath sshPath = SshSettings::sshFilePath();
CommandLine cmd { sshPath };
@@ -871,10 +871,10 @@ public:
return output;
}
void setSshParameters(const SshConnectionParameters &sshParameters)
void setSshParameters(const SshParameters &sshParameters)
{
QMutexLocker locker(&m_mutex);
const SshConnectionParameters displaylessSshParameters = displayless(sshParameters);
const SshParameters displaylessSshParameters = displayless(sshParameters);
if (m_displaylessSshParameters == displaylessSshParameters)
return;
@@ -888,7 +888,7 @@ public:
}
QString attachToSharedConnection(SshConnectionHandle *connectionHandle,
const SshConnectionParameters &sshParameters)
const SshParameters &sshParameters)
{
setSshParameters(sshParameters);
@@ -938,7 +938,7 @@ public:
}
// Call me with shell mutex locked, called from other thread
bool isRunning(const SshConnectionParameters &sshParameters) const
bool isRunning(const SshParameters &sshParameters) const
{
if (!m_shell)
return false;
@@ -949,7 +949,7 @@ public:
}
private:
mutable QMutex m_mutex;
SshConnectionParameters m_displaylessSshParameters;
SshParameters m_displaylessSshParameters;
QList<SshSharedConnection *> m_connections;
std::unique_ptr<QtcProcess> m_shell;
};
@@ -1143,7 +1143,7 @@ LinuxDevicePrivate::~LinuxDevicePrivate()
// Call me with shell mutex locked
bool LinuxDevicePrivate::setupShell()
{
const SshConnectionParameters sshParameters = q->sshParameters();
const SshParameters sshParameters = q->sshParameters();
if (m_handler->isRunning(sshParameters))
return true;
@@ -1186,7 +1186,7 @@ QByteArray LinuxDevicePrivate::outputForRunInShell(const CommandLine &cmd)
}
void LinuxDevicePrivate::attachToSharedConnection(SshConnectionHandle *connectionHandle,
const SshConnectionParameters &sshParameters)
const SshParameters &sshParameters)
{
QString socketFilePath;
QMetaObject::invokeMethod(m_handler, [this, connectionHandle, sshParameters] {
@@ -1481,7 +1481,7 @@ protected:
: m_method(method)
, m_process(this)
{
SshConnectionParameters::setupSshEnvironment(&m_process);
SshParameters::setupSshEnvironment(&m_process);
connect(&m_process, &QtcProcess::readyReadStandardOutput, this, [this] {
emit progress(QString::fromLocal8Bit(m_process.readAllStandardOutput()));
});
@@ -1583,7 +1583,7 @@ private:
m_process.setStandardInputFile(m_batchFile->fileName());
// TODO: Add support for shared ssh connection
const SshConnectionParameters params = displayless(m_device->sshParameters());
const SshParameters params = displayless(m_device->sshParameters());
m_process.setCommand(CommandLine(sftpBinary,
params.connectionOptions(sftpBinary) << params.host()));
m_process.start();
@@ -1625,7 +1625,7 @@ private:
{
m_process.close();
const SshConnectionParameters parameters = displayless(m_device->sshParameters());
const SshParameters parameters = displayless(m_device->sshParameters());
const QStringList connectionOptions // TODO: add shared connection here
= parameters.connectionOptions(SshSettings::sshFilePath());
const QString sshCmdLine = ProcessArgs::joinArgs(
@@ -26,7 +26,7 @@
#include "publickeydeploymentdialog.h"
#include <projectexplorer/devicesupport/idevice.h>
#include <ssh/sshconnection.h>
#include <ssh/sshparameters.h>
#include <utils/qtcprocess.h>
#include <utils/theme/theme.h>
@@ -32,7 +32,6 @@
#include <utils/qtcprocess.h>
using namespace ProjectExplorer;
using namespace QSsh;
using namespace Utils;
namespace RemoteLinux {
@@ -38,7 +38,6 @@
#include <utils/qtcprocess.h>
using namespace ProjectExplorer;
using namespace QSsh;
using namespace Utils;
namespace RemoteLinux {
@@ -32,9 +32,6 @@
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
#include <ssh/sshconnection.h>
#include <ssh/sshconnectionmanager.h>
#include <QDateTime>
#include <QDir>
#include <QFile>
-1
View File
@@ -17,7 +17,6 @@ add_subdirectory(profilewriter)
add_subdirectory(qml)
add_subdirectory(runextensions)
add_subdirectory(sdktool)
add_subdirectory(ssh)
add_subdirectory(toolchaincache)
add_subdirectory(tracing)
add_subdirectory(treeviewfind)
-1
View File
@@ -20,7 +20,6 @@ Project {
"qml/qml.qbs",
"runextensions/runextensions.qbs",
"sdktool/sdktool.qbs",
"ssh/ssh.qbs",
"toolchaincache/toolchaincache.qbs",
"tracing/tracing.qbs",
"treeviewfind/treeviewfind.qbs",
-9
View File
@@ -1,9 +0,0 @@
file(RELATIVE_PATH RELATIVE_TEST_PATH "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}")
file(RELATIVE_PATH TEST_RELATIVE_LIBEXEC_PATH "/${RELATIVE_TEST_PATH}" "/${IDE_LIBEXEC_PATH}")
add_qtc_test(tst_ssh
DEFINES "TEST_RELATIVE_LIBEXEC_PATH=\"${TEST_RELATIVE_LIBEXEC_PATH}\""
WITH_TESTS
DEPENDS Utils QtcSsh
SOURCES tst_ssh.cpp
)
-17
View File
@@ -1,17 +0,0 @@
import qbs.FileInfo
QtcAutotest {
name: "SSH autotest"
Depends { name: "QtcSsh" }
Depends { name: "Utils" }
files: "tst_ssh.cpp"
cpp.defines: {
var defines = base;
var absLibExecPath = FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix,
qtc.ide_libexec_path);
var relLibExecPath = FileInfo.relativePath(destinationDirectory, absLibExecPath);
defines.push('TEST_RELATIVE_LIBEXEC_PATH="' + relLibExecPath + '"');
defines.push("WITH_TESTS");
return defines;
}
}
-207
View File
@@ -1,207 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include <ssh/sshconnection.h>
#include <ssh/sshsettings.h>
#include <utils/algorithm.h>
#include <utils/environment.h>
#include <utils/launcherinterface.h>
#include <utils/qtcprocess.h>
#include <utils/singleton.h>
#include <utils/temporarydirectory.h>
#include <QDateTime>
#include <QDir>
#include <QEventLoop>
#include <QRandomGenerator>
#include <QStringList>
#include <QTemporaryDir>
#include <QTimer>
#include <QtTest>
#include <cstdlib>
using namespace QSsh;
using namespace Utils;
class tst_Ssh : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void errorHandling_data();
void errorHandling();
void pristineConnectionObject();
void remoteProcessInput();
void sftp();
void cleanupTestCase();
private:
bool waitForConnection(SshConnection &connection);
};
void tst_Ssh::initTestCase()
{
const SshConnectionParameters params = SshTest::getParameters();
if (!SshTest::checkParameters(params))
SshTest::printSetupHelp();
LauncherInterface::setPathToLauncher(qApp->applicationDirPath() + '/'
+ QLatin1String(TEST_RELATIVE_LIBEXEC_PATH));
TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath()
+ "/qtc-ssh-autotest-XXXXXX");
}
void tst_Ssh::errorHandling_data()
{
QTest::addColumn<QString>("host");
QTest::addColumn<quint16>("port");
QTest::addColumn<SshConnectionParameters::AuthenticationType>("authType");
QTest::addColumn<QString>("user");
QTest::addColumn<QString>("keyFile");
QTest::newRow("no host")
<< QString("hgdfxgfhgxfhxgfchxgcf") << quint16(12345)
<< SshConnectionParameters::AuthenticationTypeAll << QString("egal") << QString();
const QString theHost = SshTest::getHostFromEnvironment();
if (theHost.isEmpty())
return;
const quint16 thePort = SshTest::getPortFromEnvironment();
QTest::newRow("non-existing key file")
<< theHost << thePort << SshConnectionParameters::AuthenticationTypeSpecificKey
<< QString("root") << QString("somefilenamethatwedontexpecttocontainavalidkey");
}
void tst_Ssh::errorHandling()
{
if (SshSettings::sshFilePath().isEmpty())
QSKIP("No ssh found in PATH - skipping this test.");
QFETCH(QString, host);
QFETCH(quint16, port);
QFETCH(SshConnectionParameters::AuthenticationType, authType);
QFETCH(QString, user);
QFETCH(QString, keyFile);
SshConnectionParameters params;
params.setHost(host);
params.setPort(port);
params.setUserName(user);
params.timeout = 3;
params.authenticationType = authType;
params.privateKeyFile = FilePath::fromString(keyFile);
SshConnection connection(params);
QEventLoop loop;
bool disconnected = false;
QObject::connect(&connection, &SshConnection::connected, &loop, &QEventLoop::quit);
QObject::connect(&connection, &SshConnection::errorOccurred, &loop, &QEventLoop::quit);
QObject::connect(&connection, &SshConnection::disconnected,
[&disconnected] { disconnected = true; });
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
timer.setSingleShot(true);
timer.start((params.timeout + 15) * 1000);
connection.connectToHost();
loop.exec();
QVERIFY(timer.isActive());
const bool expectConnected = !SshSettings::connectionSharingEnabled();
QCOMPARE(connection.state(), expectConnected ? SshConnection::Connected
: SshConnection::Unconnected);
QCOMPARE(connection.errorString().isEmpty(), expectConnected);
QVERIFY(!disconnected);
}
void tst_Ssh::pristineConnectionObject()
{
QSsh::SshConnection connection((SshConnectionParameters()));
QCOMPARE(connection.state(), SshConnection::Unconnected);
QRegularExpression assertToIgnore(
"SOFT ASSERT: \"state\\(\\) == Connected\" in file .*[/\\\\]sshconnection.cpp, line \\d*");
QTest::ignoreMessage(QtDebugMsg, assertToIgnore);
}
void tst_Ssh::remoteProcessInput()
{
const SshConnectionParameters params = SshTest::getParameters();
if (!SshTest::checkParameters(params))
QSKIP("Insufficient setup - set QTC_SSH_TEST_* variables.");
SshConnection connection(params);
QVERIFY(waitForConnection(connection));
}
void tst_Ssh::sftp()
{
// Connect to server
const SshConnectionParameters params = SshTest::getParameters();
if (!SshTest::checkParameters(params))
QSKIP("Insufficient setup - set QTC_SSH_TEST_* variables.");
SshConnection connection(params);
QVERIFY(waitForConnection(connection));
// Create and upload 1000 small files and one big file
QTemporaryDir dirForFilesToUpload;
QTemporaryDir dirForFilesToDownload;
QTemporaryDir dir2ForFilesToDownload;
QVERIFY2(dirForFilesToUpload.isValid(), qPrintable(dirForFilesToUpload.errorString()));
QVERIFY2(dirForFilesToDownload.isValid(), qPrintable(dirForFilesToDownload.errorString()));
QVERIFY2(dir2ForFilesToDownload.isValid(), qPrintable(dirForFilesToDownload.errorString()));
const QString bigFileName("sftpbigfile");
QFile bigFile(dirForFilesToUpload.path() + '/' + bigFileName);
QVERIFY2(bigFile.open(QIODevice::WriteOnly), qPrintable(bigFile.errorString()));
const int bigFileSize = 100 * 1024 * 1024;
const int blockSize = 8192;
const int blockCount = bigFileSize / blockSize;
for (int block = 0; block < blockCount; ++block) {
int content[blockSize / sizeof(int)];
for (size_t j = 0; j < sizeof content / sizeof content[0]; ++j)
content[j] = QRandomGenerator::global()->generate();
bigFile.write(reinterpret_cast<char *>(content), sizeof content);
}
bigFile.close();
QVERIFY2(bigFile.error() == QFile::NoError, qPrintable(bigFile.errorString()));
}
void tst_Ssh::cleanupTestCase()
{
Singleton::deleteAll();
}
bool tst_Ssh::waitForConnection(SshConnection &connection)
{
QEventLoop loop;
QObject::connect(&connection, &SshConnection::connected, &loop, &QEventLoop::quit);
QObject::connect(&connection, &SshConnection::errorOccurred, &loop, &QEventLoop::quit);
connection.connectToHost();
loop.exec();
if (!connection.errorString().isEmpty())
qDebug() << connection.errorString();
return connection.state() == SshConnection::Connected && connection.errorString().isEmpty();
}
QTEST_MAIN(tst_Ssh)
#include <tst_ssh.moc>