2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2010-07-12 09:33:22 +02:00
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2010-07-12 09:33:22 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2010-04-26 11:43:25 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** 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
|
2016-01-15 14:58:39 +01:00
|
|
|
** 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.
|
2010-04-26 11:43:25 +02:00
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** 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.
|
2010-12-17 16:01:08 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2010-04-26 11:43:25 +02:00
|
|
|
|
|
|
|
|
#include "sshconnection.h"
|
2018-11-23 11:07:57 +01:00
|
|
|
|
|
|
|
|
#include "sftpsession.h"
|
|
|
|
|
#include "sftptransfer.h"
|
2016-01-14 17:11:03 +01:00
|
|
|
#include "sshlogging_p.h"
|
2018-11-23 11:07:57 +01:00
|
|
|
#include "sshprocess_p.h"
|
2012-06-19 13:03:48 +02:00
|
|
|
#include "sshremoteprocess.h"
|
2018-11-23 11:07:57 +01:00
|
|
|
#include "sshsettings.h"
|
|
|
|
|
|
|
|
|
|
#include <utils/filesystemwatcher.h>
|
|
|
|
|
#include <utils/fileutils.h>
|
|
|
|
|
#include <utils/hostosinfo.h>
|
|
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
#include <utils/temporarydirectory.h>
|
|
|
|
|
|
|
|
|
|
#include <QByteArrayList>
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QTemporaryDir>
|
|
|
|
|
#include <QTimer>
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
#include <memory>
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2011-03-02 17:13:33 +01:00
|
|
|
/*!
|
2012-05-18 10:49:35 +02:00
|
|
|
\class QSsh::SshConnection
|
2011-03-02 17:13:33 +01:00
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
\brief The SshConnection class provides an SSH connection via an OpenSSH client
|
|
|
|
|
running in master mode.
|
2011-03-02 17:13:33 +01:00
|
|
|
|
|
|
|
|
It operates asynchronously (non-blocking) and is not thread-safe.
|
2018-11-23 11:07:57 +01:00
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
2011-03-02 17:13:33 +01:00
|
|
|
*/
|
|
|
|
|
|
2012-05-18 10:49:35 +02:00
|
|
|
namespace QSsh {
|
2018-11-23 11:07:57 +01:00
|
|
|
using namespace Internal;
|
|
|
|
|
using namespace Utils;
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
SshConnectionParameters::SshConnectionParameters()
|
2010-08-24 10:51:31 +02:00
|
|
|
{
|
2017-12-19 12:45:46 +01:00
|
|
|
url.setPort(0);
|
2010-08-24 10:51:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool equals(const SshConnectionParameters &p1, const SshConnectionParameters &p2)
|
|
|
|
|
{
|
2017-12-19 12:45:46 +01:00
|
|
|
return p1.url == p2.url
|
2011-02-28 17:01:53 +01:00
|
|
|
&& p1.authenticationType == p2.authenticationType
|
2017-12-19 12:45:46 +01:00
|
|
|
&& p1.privateKeyFile == p2.privateKeyFile
|
2014-11-12 16:50:04 +01:00
|
|
|
&& p1.hostKeyCheckingMode == p2.hostKeyCheckingMode
|
2018-11-23 11:07:57 +01:00
|
|
|
&& p1.x11DisplayName == p2.x11DisplayName
|
2017-12-19 12:45:46 +01:00
|
|
|
&& p1.timeout == p2.timeout;
|
2010-08-24 10:51:31 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-18 10:49:35 +02:00
|
|
|
bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2)
|
2010-08-24 10:51:31 +02:00
|
|
|
{
|
|
|
|
|
return equals(p1, p2);
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-18 10:49:35 +02:00
|
|
|
bool operator!=(const SshConnectionParameters &p1, const SshConnectionParameters &p2)
|
2010-08-24 10:51:31 +02:00
|
|
|
{
|
|
|
|
|
return !equals(p1, p2);
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
struct SshConnection::SshConnectionPrivate
|
2012-06-20 15:55:30 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
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;
|
2012-06-20 15:55:30 +02:00
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
QString socketFilePath() const
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(masterSocketDir, return QString());
|
|
|
|
|
return masterSocketDir->path() + "/control_socket";
|
2013-06-18 18:12:34 +02:00
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2018-12-14 15:41:59 +01:00
|
|
|
QStringList connectionOptions() const
|
2018-11-23 11:07:57 +01:00
|
|
|
{
|
|
|
|
|
QString hostKeyCheckingString;
|
|
|
|
|
switch (connParams.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", "User=" + connParams.userName(),
|
|
|
|
|
"-o", "Port=" + QString::number(connParams.port())};
|
|
|
|
|
const bool keyOnly = connParams.authenticationType ==
|
|
|
|
|
SshConnectionParameters::AuthenticationTypeSpecificKey;
|
|
|
|
|
if (keyOnly)
|
|
|
|
|
args << "-i" << connParams.privateKeyFile;
|
|
|
|
|
if (keyOnly || SshSettings::askpassFilePath().isEmpty())
|
|
|
|
|
args << "-o" << "BatchMode=yes";
|
|
|
|
|
if (sharingEnabled)
|
|
|
|
|
args << "-o" << ("ControlPath=" + socketFilePath());
|
|
|
|
|
if (connParams.timeout != 0)
|
|
|
|
|
args << "-o" << ("ConnectTimeout=" + QString::number(connParams.timeout));
|
2018-12-14 15:41:59 +01:00
|
|
|
return args;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList connectionArgs() const
|
|
|
|
|
{
|
|
|
|
|
return connectionOptions() << connParams.host();
|
2018-11-23 11:07:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SshConnectionParameters connParams;
|
|
|
|
|
SshConnectionInfo connInfo;
|
|
|
|
|
SshProcess masterProcess;
|
|
|
|
|
QString errorString;
|
|
|
|
|
std::unique_ptr<TemporaryDirectory> masterSocketDir;
|
|
|
|
|
State state = Unconnected;
|
|
|
|
|
const bool sharingEnabled = SshSettings::connectionSharingEnabled();
|
|
|
|
|
};
|
2010-05-05 10:06:31 +02:00
|
|
|
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
SshConnection::SshConnection(const SshConnectionParameters &serverInfo, QObject *parent)
|
|
|
|
|
: QObject(parent), d(new SshConnectionPrivate)
|
2010-07-12 09:33:22 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
qRegisterMetaType<QSsh::SftpFileInfo>("QSsh::SftpFileInfo");
|
|
|
|
|
qRegisterMetaType<QList <QSsh::SftpFileInfo> >("QList<QSsh::SftpFileInfo>");
|
|
|
|
|
d->connParams = serverInfo;
|
|
|
|
|
connect(&d->masterProcess, &QProcess::started, [this] {
|
|
|
|
|
QFileInfo socketInfo(d->socketFilePath());
|
|
|
|
|
if (socketInfo.exists()) {
|
|
|
|
|
emitConnected();
|
2010-08-16 12:40:55 +02:00
|
|
|
return;
|
2012-10-11 15:34:33 +02:00
|
|
|
}
|
2018-12-17 14:08:13 +01:00
|
|
|
auto * const socketWatcher = new FileSystemWatcher(this);
|
|
|
|
|
auto * const socketWatcherTimer = new QTimer(this);
|
|
|
|
|
const auto socketFileChecker = [this, socketWatcher, socketWatcherTimer] {
|
2018-11-23 11:07:57 +01:00
|
|
|
if (!QFileInfo::exists(d->socketFilePath()))
|
|
|
|
|
return;
|
2018-12-17 14:08:13 +01:00
|
|
|
socketWatcher->disconnect();
|
|
|
|
|
socketWatcher->deleteLater();
|
|
|
|
|
socketWatcherTimer->disconnect();
|
|
|
|
|
socketWatcherTimer->stop();
|
|
|
|
|
socketWatcherTimer->deleteLater();
|
2018-11-23 11:07:57 +01:00
|
|
|
emitConnected();
|
|
|
|
|
};
|
2018-12-17 14:08:13 +01:00
|
|
|
connect(socketWatcher, &FileSystemWatcher::directoryChanged, socketFileChecker);
|
|
|
|
|
socketWatcher->addDirectory(socketInfo.path(), FileSystemWatcher::WatchAllChanges);
|
2018-11-23 11:07:57 +01:00
|
|
|
if (HostOsInfo::isMacHost()) {
|
|
|
|
|
// QTBUG-72455
|
2018-12-17 14:08:13 +01:00
|
|
|
socketWatcherTimer->setInterval(1000);
|
|
|
|
|
connect(socketWatcherTimer, &QTimer::timeout, socketFileChecker);
|
|
|
|
|
socketWatcherTimer->start();
|
2012-10-11 15:34:33 +02:00
|
|
|
}
|
2018-11-23 11:07:57 +01:00
|
|
|
});
|
|
|
|
|
connect(&d->masterProcess, &QProcess::errorOccurred, [this] (QProcess::ProcessError error) {
|
|
|
|
|
switch (error) {
|
|
|
|
|
case QProcess::FailedToStart:
|
|
|
|
|
emitError(tr("Cannot establish SSH connection: Control process failed to start: %1")
|
|
|
|
|
.arg(d->fullProcessError()));
|
|
|
|
|
break;
|
|
|
|
|
case QProcess::Crashed: // Handled by finished() handler.
|
|
|
|
|
case QProcess::Timedout:
|
|
|
|
|
case QProcess::ReadError:
|
|
|
|
|
case QProcess::WriteError:
|
|
|
|
|
case QProcess::UnknownError:
|
|
|
|
|
break; // Cannot happen.
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
connect(&d->masterProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished), [this] {
|
|
|
|
|
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()) {
|
|
|
|
|
QProcessEnvironment env = d->masterProcess.processEnvironment();
|
|
|
|
|
env.insert("DISPLAY", d->connParams.x11DisplayName);
|
|
|
|
|
d->masterProcess.setProcessEnvironment(env);
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
void SshConnection::connectToHost()
|
2010-05-10 11:01:56 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
d->state = Connecting;
|
|
|
|
|
QTimer::singleShot(0, this, &SshConnection::doConnectToHost);
|
2010-05-10 11:01:56 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
void SshConnection::disconnectFromHost()
|
2010-07-12 09:33:22 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
switch (d->state) {
|
|
|
|
|
case Connecting:
|
|
|
|
|
case Connected:
|
|
|
|
|
if (!d->sharingEnabled) {
|
|
|
|
|
emitDisconnected();
|
2016-07-20 18:04:56 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2018-11-23 11:07:57 +01:00
|
|
|
d->state = Disconnecting;
|
|
|
|
|
if (HostOsInfo::isWindowsHost())
|
|
|
|
|
d->masterProcess.kill();
|
|
|
|
|
else
|
|
|
|
|
d->masterProcess.terminate();
|
|
|
|
|
break;
|
|
|
|
|
case Unconnected:
|
|
|
|
|
case Disconnecting:
|
2013-06-18 18:12:34 +02:00
|
|
|
break;
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2013-06-18 18:12:34 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
SshConnection::State SshConnection::state() const
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
return d->state;
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
QString SshConnection::errorString() const
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
return d->errorString;
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
SshConnectionParameters SshConnection::connectionParameters() const
|
2010-07-12 09:33:22 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
return d->connParams;
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2016-07-20 18:04:56 +02:00
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
SshConnectionInfo SshConnection::connectionInfo() const
|
2016-07-20 18:04:56 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
QTC_ASSERT(state() == Connected, return SshConnectionInfo());
|
|
|
|
|
if (d->connInfo.isValid())
|
|
|
|
|
return d->connInfo;
|
|
|
|
|
QProcess p;
|
|
|
|
|
p.start(SshSettings::sshFilePath().toString(), d->connectionArgs() << "echo" << "-n"
|
|
|
|
|
<< "$SSH_CLIENT");
|
|
|
|
|
if (!p.waitForStarted() || !p.waitForFinished()) {
|
|
|
|
|
qCWarning(Internal::sshLog) << "failed to retrieve connection info:" << p.errorString();
|
|
|
|
|
return SshConnectionInfo();
|
2016-07-20 18:04:56 +02:00
|
|
|
}
|
2018-11-23 11:07:57 +01:00
|
|
|
const QByteArrayList data = p.readAllStandardOutput().split(' ');
|
|
|
|
|
if (data.size() != 3) {
|
|
|
|
|
qCWarning(Internal::sshLog) << "failed to retrieve connection info: unexpected output";
|
|
|
|
|
return SshConnectionInfo();
|
2016-07-20 18:04:56 +02:00
|
|
|
}
|
2018-11-23 11:07:57 +01:00
|
|
|
d->connInfo.localPort = data.at(1).toInt();
|
|
|
|
|
if (d->connInfo.localPort == 0) {
|
|
|
|
|
qCWarning(Internal::sshLog) << "failed to retrieve connection info: unexpected output";
|
|
|
|
|
return SshConnectionInfo();
|
2016-07-20 18:04:56 +02:00
|
|
|
}
|
2018-11-23 11:07:57 +01:00
|
|
|
if (!d->connInfo.localAddress.setAddress(QString::fromLatin1(data.first()))) {
|
|
|
|
|
qCWarning(Internal::sshLog) << "failed to retrieve connection info: unexpected output";
|
|
|
|
|
return SshConnectionInfo();
|
2011-02-11 14:00:54 +01:00
|
|
|
}
|
2018-11-23 11:07:57 +01:00
|
|
|
d->connInfo.peerPort = d->connParams.port();
|
|
|
|
|
d->connInfo.peerAddress.setAddress(d->connParams.host());
|
|
|
|
|
return d->connInfo;
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2018-12-14 15:41:59 +01:00
|
|
|
QStringList SshConnection::connectionOptions() const
|
|
|
|
|
{
|
|
|
|
|
return d->connectionOptions();
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
bool SshConnection::sharingEnabled() const
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
return d->sharingEnabled;
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
SshConnection::~SshConnection()
|
2016-03-31 18:57:03 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
disconnect();
|
|
|
|
|
disconnectFromHost();
|
|
|
|
|
delete d;
|
2016-03-31 18:57:03 +02:00
|
|
|
}
|
2011-02-11 14:00:54 +01:00
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
SshRemoteProcessPtr SshConnection::createRemoteProcess(const QByteArray &command)
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
QTC_ASSERT(state() == Connected, return SshRemoteProcessPtr());
|
|
|
|
|
return SshRemoteProcessPtr(new SshRemoteProcess(command, d->connectionArgs()));
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
SshRemoteProcessPtr SshConnection::createRemoteShell()
|
2016-07-20 18:04:56 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
return createRemoteProcess(QByteArray());
|
2016-07-20 18:04:56 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
SftpTransferPtr SshConnection::createUpload(const FilesToTransfer &files,
|
|
|
|
|
FileTransferErrorHandling errorHandlingMode)
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
return setupTransfer(files, Internal::FileTransferType::Upload, errorHandlingMode);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
SftpTransferPtr SshConnection::createDownload(const FilesToTransfer &files,
|
|
|
|
|
FileTransferErrorHandling errorHandlingMode)
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
return setupTransfer(files, Internal::FileTransferType::Download, errorHandlingMode);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
SftpSessionPtr SshConnection::createSftpSession()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
QTC_ASSERT(state() == Connected, return SftpSessionPtr());
|
|
|
|
|
return SftpSessionPtr(new SftpSession(d->connectionArgs()));
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
void SshConnection::doConnectToHost()
|
2011-02-11 14:00:54 +01:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
if (d->state != Connecting)
|
2011-04-28 11:12:34 +02:00
|
|
|
return;
|
2018-11-23 11:07:57 +01:00
|
|
|
const FileName sshBinary = SshSettings::sshFilePath();
|
|
|
|
|
if (!sshBinary.exists()) {
|
|
|
|
|
emitError(tr("Cannot establish SSH connection: ssh binary \"%1\" does not exist.")
|
|
|
|
|
.arg(sshBinary.toUserOutput()));
|
2016-07-20 18:04:56 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2018-11-23 11:07:57 +01:00
|
|
|
if (!d->sharingEnabled)
|
|
|
|
|
emitConnected();
|
|
|
|
|
QTC_ASSERT(TemporaryDirectory::masterTemporaryDirectory(), return);
|
|
|
|
|
d->masterSocketDir.reset(new TemporaryDirectory("qtc-ssh-XXXXXX"));
|
|
|
|
|
if (!d->masterSocketDir->isValid()) {
|
|
|
|
|
emitError(tr("Cannot establish SSH connection: Failed to create temporary "
|
|
|
|
|
"directory for control socket: %1")
|
|
|
|
|
.arg(d->masterSocketDir->errorString()));
|
2010-07-12 09:33:22 +02:00
|
|
|
return;
|
2018-01-03 17:56:52 +01:00
|
|
|
}
|
2018-11-23 11:07:57 +01:00
|
|
|
QStringList args = QStringList{"-M", "-N", "-o", "ControlPersist=no"} << d->connectionArgs();
|
|
|
|
|
if (!d->connParams.x11DisplayName.isEmpty())
|
|
|
|
|
args.prepend("-X");
|
|
|
|
|
qCDebug(sshLog) << "establishing connection:" << sshBinary.toUserOutput() << args;
|
|
|
|
|
d->masterProcess.start(sshBinary.toString(), args);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
void SshConnection::emitError(const QString &reason)
|
2010-08-16 12:40:55 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
const State oldState = d->state;
|
|
|
|
|
d->state = Unconnected;
|
|
|
|
|
d->errorString = reason;
|
|
|
|
|
emit errorOccurred();
|
|
|
|
|
if (oldState == Connected)
|
|
|
|
|
emitDisconnected();
|
2010-08-16 12:40:55 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
void SshConnection::emitConnected()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
d->state = Connected;
|
|
|
|
|
emit connected();
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
void SshConnection::emitDisconnected()
|
2012-06-19 13:03:48 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
d->state = Unconnected;
|
|
|
|
|
emit disconnected();
|
2016-03-31 18:57:03 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:07:57 +01:00
|
|
|
SftpTransferPtr SshConnection::setupTransfer(
|
|
|
|
|
const FilesToTransfer &files, Internal::FileTransferType type,
|
|
|
|
|
FileTransferErrorHandling errorHandlingMode)
|
2016-03-31 18:57:03 +02:00
|
|
|
{
|
2018-11-23 11:07:57 +01:00
|
|
|
QTC_ASSERT(state() == Connected, return SftpTransferPtr());
|
|
|
|
|
return SftpTransferPtr(new SftpTransfer(files, type, errorHandlingMode, d->connectionArgs()));
|
2012-06-19 13:03:48 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-18 10:49:35 +02:00
|
|
|
} // namespace QSsh
|