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:
Christian Kandeler
2011-11-15 17:13:02 +01:00
parent d9dde0d5e8
commit 4c76e40617
17 changed files with 171 additions and 91 deletions

View File

@@ -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