forked from qt-creator/qt-creator
SSH: Derive SshRemoteProcess from QIODevice.
Now it looks even more like QProcess. Things like process channels are still missing. Change-Id: I3f30cd00ed4a054d02e83add9a6f4162b48f8345 Reviewed-by: Christian Kandeler <christian.kandeler@nokia.com>
This commit is contained in:
@@ -821,13 +821,13 @@ void SftpChannelPrivate::handleOpenSuccessInternal()
|
||||
m_sftpState = SubsystemRequested;
|
||||
}
|
||||
|
||||
void SftpChannelPrivate::handleOpenFailureInternal()
|
||||
void SftpChannelPrivate::handleOpenFailureInternal(const QString &reason)
|
||||
{
|
||||
if (channelState() != SessionRequested) {
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE packet.");
|
||||
}
|
||||
emit initializationFailed(tr("Server could not start session."));
|
||||
emit initializationFailed(tr("Server could not start session: %1").arg(reason));
|
||||
}
|
||||
|
||||
void SftpChannelPrivate::sendReadRequest(const SftpDownload::Ptr &job,
|
||||
|
||||
@@ -74,7 +74,7 @@ private:
|
||||
SftpJobId createJob(const AbstractSftpOperation::Ptr &job);
|
||||
|
||||
virtual void handleOpenSuccessInternal();
|
||||
virtual void handleOpenFailureInternal();
|
||||
virtual void handleOpenFailureInternal(const QString &reason);
|
||||
virtual void handleChannelDataInternal(const QByteArray &data);
|
||||
virtual void handleChannelExtendedDataInternal(quint32 type,
|
||||
const QByteArray &data);
|
||||
|
||||
@@ -84,7 +84,7 @@ void AbstractSshChannel::requestSessionStart()
|
||||
setChannelState(SessionRequested);
|
||||
m_timeoutTimer->start(ReplyTimeout);
|
||||
} catch (Botan::Exception &e) {
|
||||
m_errorString = QString::fromAscii(e.what());
|
||||
qDebug("Botan error: %s", e.what());
|
||||
closeChannel();
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@ void AbstractSshChannel::sendData(const QByteArray &data)
|
||||
m_sendBuffer += data;
|
||||
flushSendBuffer();
|
||||
} catch (Botan::Exception &e) {
|
||||
m_errorString = QString::fromAscii(e.what());
|
||||
qDebug("Botan error: %s", e.what());
|
||||
closeChannel();
|
||||
}
|
||||
}
|
||||
@@ -163,8 +163,7 @@ void AbstractSshChannel::handleOpenFailure(const QString &reason)
|
||||
#ifdef CREATOR_SSH_DEBUG
|
||||
qDebug("Channel open request failed for channel %u", m_localChannel);
|
||||
#endif
|
||||
m_errorString = reason;
|
||||
handleOpenFailureInternal();
|
||||
handleOpenFailureInternal(reason);
|
||||
}
|
||||
|
||||
void AbstractSshChannel::handleChannelEof()
|
||||
|
||||
@@ -58,9 +58,6 @@ public:
|
||||
ChannelState channelState() const { return m_state; }
|
||||
void setChannelState(ChannelState state);
|
||||
|
||||
void setError(const QString &error) { m_errorString = error; }
|
||||
QString errorString() const { return m_errorString; }
|
||||
|
||||
quint32 localChannelId() const { return m_localChannel; }
|
||||
quint32 remoteChannel() const { return m_remoteChannel; }
|
||||
|
||||
@@ -101,7 +98,7 @@ protected:
|
||||
|
||||
private:
|
||||
virtual void handleOpenSuccessInternal() = 0;
|
||||
virtual void handleOpenFailureInternal() = 0;
|
||||
virtual void handleOpenFailureInternal(const QString &reason) = 0;
|
||||
virtual void handleChannelDataInternal(const QByteArray &data) = 0;
|
||||
virtual void handleChannelExtendedDataInternal(quint32 type,
|
||||
const QByteArray &data) = 0;
|
||||
@@ -119,7 +116,6 @@ private:
|
||||
quint32 m_remoteMaxPacketSize;
|
||||
ChannelState m_state;
|
||||
QByteArray m_sendBuffer;
|
||||
QString m_errorString;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
/*!
|
||||
\class Utils::SshRemoteProcess
|
||||
|
||||
@@ -49,17 +51,10 @@
|
||||
|
||||
Objects are created via SshConnection::createRemoteProcess.
|
||||
The process is started via the start() member function.
|
||||
A closeChannel() function is provided, but rarely useful, because
|
||||
|
||||
\list
|
||||
\i a) when the process ends, the channel is closed automatically, and
|
||||
\i b) closing a channel will not necessarily kill the remote process.
|
||||
\endlist
|
||||
|
||||
Therefore, the only sensible use case for calling closeChannel() is to
|
||||
get rid of an SshRemoteProces object before the process is actually started.
|
||||
If the process needs a pseudo terminal, you can request one
|
||||
via requestTerminal() before calling start().
|
||||
Note that this class does not support QIODevice's waitFor*() functions, i.e. it has
|
||||
no synchronous mode.
|
||||
*/
|
||||
|
||||
namespace Utils {
|
||||
@@ -99,12 +94,63 @@ SshRemoteProcess::~SshRemoteProcess()
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool SshRemoteProcess::atEnd() const
|
||||
{
|
||||
return QIODevice::atEnd() && d->m_stdout.isEmpty();
|
||||
}
|
||||
|
||||
qint64 SshRemoteProcess::bytesAvailable() const
|
||||
{
|
||||
return QIODevice::bytesAvailable() + d->m_stdout.count();
|
||||
}
|
||||
|
||||
bool SshRemoteProcess::canReadLine() const
|
||||
{
|
||||
return QIODevice::canReadLine() || d->m_stdout.contains('\n'); // TODO: Not cross-platform?
|
||||
}
|
||||
|
||||
QByteArray SshRemoteProcess::readAllStandardOutput()
|
||||
{
|
||||
return readAll();
|
||||
}
|
||||
|
||||
QByteArray SshRemoteProcess::readAllStandardError()
|
||||
{
|
||||
const QByteArray data = d->m_stderr;
|
||||
d->m_stderr.clear();
|
||||
return data;
|
||||
}
|
||||
|
||||
void SshRemoteProcess::close()
|
||||
{
|
||||
d->closeChannel();
|
||||
QIODevice::close();
|
||||
}
|
||||
|
||||
qint64 SshRemoteProcess::readData(char *data, qint64 maxlen)
|
||||
{
|
||||
const qint64 bytesRead = qMin(qint64(d->m_stdout.count()), maxlen);
|
||||
memcpy(data, d->m_stdout.constData(), bytesRead);
|
||||
d->m_stdout.remove(0, bytesRead);
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
qint64 SshRemoteProcess::writeData(const char *data, qint64 len)
|
||||
{
|
||||
if (isRunning()) {
|
||||
d->sendData(QByteArray(data, len));
|
||||
return len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SshRemoteProcess::init()
|
||||
{
|
||||
connect(d, SIGNAL(started()), this, SIGNAL(started()),
|
||||
Qt::QueuedConnection);
|
||||
connect(d, SIGNAL(readyReadStandardOutput()), this, SIGNAL(readyReadStandardOutput()),
|
||||
Qt::QueuedConnection);
|
||||
connect(d, SIGNAL(readyReadStandardOutput()), this, SIGNAL(readyRead()), Qt::QueuedConnection);
|
||||
connect(d, SIGNAL(readyReadStandardError()), this,
|
||||
SIGNAL(readyReadStandardError()), Qt::QueuedConnection);
|
||||
connect(d, SIGNAL(closed(int)), this, SIGNAL(closed(int)), Qt::QueuedConnection);
|
||||
@@ -129,6 +175,7 @@ void SshRemoteProcess::start()
|
||||
#ifdef CREATOR_SSH_DEBUG
|
||||
qDebug("process start requested, channel id = %u", d->localChannelId());
|
||||
#endif
|
||||
QIODevice::open(QIODevice::ReadWrite);
|
||||
d->requestSessionStart();
|
||||
}
|
||||
}
|
||||
@@ -140,36 +187,19 @@ void SshRemoteProcess::sendSignal(const QByteArray &signal)
|
||||
d->m_sendFacility.sendChannelSignalPacket(d->remoteChannel(),
|
||||
signal);
|
||||
} catch (Botan::Exception &e) {
|
||||
d->setError(QString::fromAscii(e.what()));
|
||||
setErrorString(QString::fromAscii(e.what()));
|
||||
d->closeChannel();
|
||||
}
|
||||
}
|
||||
|
||||
void SshRemoteProcess::closeChannel()
|
||||
{
|
||||
d->closeChannel();
|
||||
}
|
||||
|
||||
void SshRemoteProcess::sendInput(const QByteArray &data)
|
||||
{
|
||||
if (isRunning())
|
||||
d->sendData(data);
|
||||
}
|
||||
|
||||
bool SshRemoteProcess::isRunning() const
|
||||
{
|
||||
return d->m_procState == Internal::SshRemoteProcessPrivate::Running;
|
||||
}
|
||||
|
||||
QString SshRemoteProcess::errorString() const { return d->errorString(); }
|
||||
|
||||
int SshRemoteProcess::exitCode() const { return d->m_exitCode; }
|
||||
|
||||
QByteArray SshRemoteProcess::exitSignal() const { return d->m_signal; }
|
||||
|
||||
QByteArray SshRemoteProcess::readAllStandardOutput() { return d->readAllStandardOutput(); }
|
||||
QByteArray SshRemoteProcess::readAllStandardError() { return d->readAllStandardError(); }
|
||||
|
||||
namespace Internal {
|
||||
|
||||
SshRemoteProcessPrivate::SshRemoteProcessPrivate(const QByteArray &command,
|
||||
@@ -214,20 +244,6 @@ void SshRemoteProcessPrivate::setProcState(ProcessState newState)
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray SshRemoteProcessPrivate::readAllStandardOutput()
|
||||
{
|
||||
const QByteArray data = m_stdout;
|
||||
m_stdout.clear();
|
||||
return data;
|
||||
}
|
||||
|
||||
QByteArray SshRemoteProcessPrivate::readAllStandardError()
|
||||
{
|
||||
const QByteArray data = m_stderr;
|
||||
m_stderr.clear();
|
||||
return data;
|
||||
}
|
||||
|
||||
void SshRemoteProcessPrivate::closeHook()
|
||||
{
|
||||
if (m_wasRunning) {
|
||||
@@ -256,9 +272,10 @@ void SshRemoteProcessPrivate::handleOpenSuccessInternal()
|
||||
m_timeoutTimer->start(ReplyTimeout);
|
||||
}
|
||||
|
||||
void SshRemoteProcessPrivate::handleOpenFailureInternal()
|
||||
void SshRemoteProcessPrivate::handleOpenFailureInternal(const QString &reason)
|
||||
{
|
||||
setProcState(StartFailed);
|
||||
m_proc->setErrorString(reason);
|
||||
}
|
||||
|
||||
void SshRemoteProcessPrivate::handleChannelSuccess()
|
||||
@@ -313,9 +330,9 @@ void SshRemoteProcessPrivate::handleExitSignal(const SshChannelExitSignal &signa
|
||||
#ifdef CREATOR_SSH_DEBUG
|
||||
qDebug("Exit due to signal %s", signal.signal.data());
|
||||
#endif
|
||||
setError(signal.error);
|
||||
m_signal = signal.signal;
|
||||
m_procState = Exited;
|
||||
m_proc->setErrorString(tr("Process killed by signal"));
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
#include <utils/utils_global.h>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@@ -50,7 +50,8 @@ class SshRemoteProcessPrivate;
|
||||
class SshSendFacility;
|
||||
} // namespace Internal
|
||||
|
||||
class QTCREATOR_UTILS_EXPORT SshRemoteProcess : public QObject
|
||||
// TODO: ProcessChannel
|
||||
class QTCREATOR_UTILS_EXPORT SshRemoteProcess : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -77,6 +78,13 @@ public:
|
||||
|
||||
~SshRemoteProcess();
|
||||
|
||||
// QIODevice stuff
|
||||
bool atEnd() const;
|
||||
qint64 bytesAvailable() const;
|
||||
bool canReadLine() const;
|
||||
void close();
|
||||
bool isSequential() const { return true; }
|
||||
|
||||
/*
|
||||
* Note that this is of limited value in practice, because servers are
|
||||
* usually configured to ignore such requests for security reasons.
|
||||
@@ -85,10 +93,8 @@ public:
|
||||
|
||||
void requestTerminal(const SshPseudoTerminal &terminal);
|
||||
void start();
|
||||
void closeChannel();
|
||||
|
||||
bool isRunning() const;
|
||||
QString errorString() const;
|
||||
int exitCode() const;
|
||||
QByteArray exitSignal() const;
|
||||
|
||||
@@ -99,8 +105,6 @@ public:
|
||||
void sendSignal(const QByteArray &signal);
|
||||
void kill() { sendSignal(KillSignal); }
|
||||
|
||||
void sendInput(const QByteArray &data); // Should usually have a trailing newline.
|
||||
|
||||
signals:
|
||||
void started();
|
||||
|
||||
@@ -118,6 +122,10 @@ private:
|
||||
Internal::SshSendFacility &sendFacility);
|
||||
SshRemoteProcess(quint32 channelId, Internal::SshSendFacility &sendFacility);
|
||||
|
||||
// QIODevice stuff
|
||||
qint64 readData(char *data, qint64 maxlen);
|
||||
qint64 writeData(const char *data, qint64 len);
|
||||
|
||||
void init();
|
||||
|
||||
Internal::SshRemoteProcessPrivate *d;
|
||||
|
||||
@@ -52,7 +52,7 @@ class SshRemoteProcessPrivate : public AbstractSshChannel
|
||||
friend class Utils::SshRemoteProcess;
|
||||
public:
|
||||
enum ProcessState {
|
||||
NotYetStarted, ExecRequested, StartFailed,Running, Exited
|
||||
NotYetStarted, ExecRequested, StartFailed, Running, Exited
|
||||
};
|
||||
|
||||
virtual void handleChannelSuccess();
|
||||
@@ -60,9 +60,6 @@ public:
|
||||
|
||||
virtual void closeHook();
|
||||
|
||||
QByteArray readAllStandardOutput();
|
||||
QByteArray readAllStandardError();
|
||||
|
||||
signals:
|
||||
void started();
|
||||
void readyReadStandardOutput();
|
||||
@@ -76,7 +73,7 @@ private:
|
||||
SshRemoteProcess *proc);
|
||||
|
||||
virtual void handleOpenSuccessInternal();
|
||||
virtual void handleOpenFailureInternal();
|
||||
virtual void handleOpenFailureInternal(const QString &reason);
|
||||
virtual void handleChannelDataInternal(const QByteArray &data);
|
||||
virtual void handleChannelExtendedDataInternal(quint32 type,
|
||||
const QByteArray &data);
|
||||
|
||||
Reference in New Issue
Block a user