Introduce new classes for client-server communication.

Still based on what we had already, though more separated.
Change-Id: I4cce298003a4ffc2ebcec01fea1a07adfbfdf990
Reviewed-by: Tim Jenssen <tim.jenssen@digia.com>
Reviewed-by: Niels Weber <niels.weber@digia.com>
This commit is contained in:
kh1 2014-06-03 10:59:40 +02:00 committed by Karsten Heimrich
parent 00c6f94d1d
commit 7c07130119
18 changed files with 2715 additions and 6 deletions

View File

@ -112,7 +112,16 @@ HEADERS += packagemanagercore.h \
metadatajob.h \
metadatajob_p.h \
installer_global.h \
scriptengine_p.h
scriptengine_p.h \
protocol.h \
remoteobject.h \
remoteclient.h \
remoteserver.h \
remoteclient_p.h \
remoteserver_p.h \
remotefileengine.h \
remoteserverconnection.h \
remoteserverconnection_p.h
SOURCES += packagemanagercore.cpp \
packagemanagercore_p.cpp \
@ -180,7 +189,12 @@ HEADERS += packagemanagercore.h \
downloadfiletask.cpp \
unziptask.cpp \
observer.cpp \
metadatajob.cpp
metadatajob.cpp \
remoteobject.cpp \
remoteclient.cpp \
remoteserver.cpp \
remotefileengine.cpp \
remoteserverconnection.cpp
RESOURCES += resources/patch_file_lists.qrc \
resources/installer.qrc

View File

@ -1,6 +1,6 @@
/**************************************************************************
**
** Copyright (C) 2012-2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.

View File

@ -0,0 +1,160 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#ifndef PROTOCOL_H
#define PROTOCOL_H
namespace QInstaller {
namespace Protocol {
const char Create[] = "Create";
const char Destroy[] = "Destroy";
const char Shutdown[] = "Shutdown";
const char Authorize[] = "Authorize";
const char DebugAuthorizationKey[] = "DebugAuthorizationKey";
// QProcessWrapper
const char QProcess[] = "QProcess";
const char QProcessCloseWriteChannel[] = "QProcess::closeWriteChannel";
const char QProcessExitCode[] = "QProcess::exitCode";
const char QProcessExitStatus[] = "QProcess::exitStatus";
const char QProcessKill[] = "QProcess::kill";
const char QProcessReadAll[] = "QProcess::readAll";
const char QProcessReadAllStandardOutput[] = "QProcess::readAllStandardOutput";
const char QProcessReadAllStandardError[] = "QProcess::readAllStandardError";
const char QProcessStartDetached[] = "QProcess::startDetached";
const char QProcessSetWorkingDirectory[] = "QProcess::setWorkingDirectory";
const char QProcessSetEnvironment[] = "QProcess::setEnvironment";
const char QProcessEnvironment[] = "QProcess::environment";
const char QProcessStart3Arg[] = "QProcess::start3";
const char QProcessStart2Arg[] = "QProcess::start2";
const char QProcessState[] = "QProcess::state";
const char QProcessTerminate[] = "QProcess::terminate";
const char QProcessWaitForFinished[] = "QProcess::waitForFinished";
const char QProcessWaitForStarted[] = "QProcess::waitForStarted";
const char QProcessWorkingDirectory[] = "QProcess::workingDirectory";
const char QProcessErrorString[] = "QProcess::errorString";
const char QProcessReadChannel[] = "QProcess::readChannel";
const char QProcessSetReadChannel[] = "QProcess::setReadChannel";
const char QProcessWrite[] = "QProcess::write";
const char QProcessProcessChannelMode[] = "QProcess::processChannelMode";
const char QProcessSetProcessChannelMode[] = "QProcess::setProcessChannelMode";
const char QProcessSetNativeArguments[] = "QProcess::setNativeArguments";
const char GetQProcessSignals[] = "GetQProcessSignals";
const char QProcessSignalBytesWritten[] = "QProcess::bytesWritten";
const char QProcessSignalAboutToClose[] = "QProcess::aboutToClose";
const char QProcessSignalReadChannelFinished[] = "QProcess::readChannelFinished";
const char QProcessSignalError[] = "QProcess::error";
const char QProcessSignalReadyReadStandardOutput[] = "QProcess::readyReadStandardOutput";
const char QProcessSignalReadyReadStandardError[] = "QProcess::readyReadStandardError";
const char QProcessSignalStarted[] = "QProcess::started";
const char QProcessSignalReadyRead[] = "QProcess::readyRead";
const char QProcessSignalStateChanged[] = "QProcess::stateChanged";
const char QProcessSignalFinished[] = "QProcess::finished";
// QSettingsWrapper
const char QSettings[] = "QSettings";
const char QSettingsAllKeys[] = "QSettings::allKeys";
const char QSettingsBeginGroup[] = "QSettings::beginGroup";
const char QSettingsBeginWriteArray[] = "QSettings::beginWriteArray";
const char QSettingsBeginReadArray[] = "QSettings::beginReadArray";
const char QSettingsChildGroups[] = "QSettings::childGroups";
const char QSettingsChildKeys[] = "QSettings::childKeys";
const char QSettingsClear[] = "QSettings::clear";
const char QSettingsContains[] = "QSettings::contains";
const char QSettingsEndArray[] = "QSettings::endArray";
const char QSettingsEndGroup[] = "QSettings::endGroup";
const char QSettingsFallbacksEnabled[] = "QSettings::fallbacksEnabled";
const char QSettingsFileName[] = "QSettings::fileName";
const char QSettingsGroup[] = "QSettings::group";
const char QSettingsIsWritable[] = "QSettings::isWritable";
const char QSettingsRemove[] = "QSettings::remove";
const char QSettingsSetArrayIndex[] = "QSettings::setArrayIndex";
const char QSettingsSetFallbacksEnabled[] = "QSettings::setFallbacksEnabled";
const char QSettingsStatus[] = "QSettings::status";
const char QSettingsSync[] = "QSettings::sync";
const char QSettingsSetValue[] = "QSettings::setValue";
const char QSettingsValue[] = "QSettings::value";
const char QSettingsOrganizationName[] = "QSettings::organizationName";
const char QSettingsApplicationName[] = "QSettings::applicationName";
// RemoteFileEngine
const char QAbstractFileEngine[] = "QAbstractFileEngine";
const char QAbstractFileEngineAtEnd[] = "QAbstractFileEngine::atEnd";
const char QAbstractFileEngineCaseSensitive[] = "QAbstractFileEngine::caseSensitive";
const char QAbstractFileEngineClose[] = "QAbstractFileEngine::close";
const char QAbstractFileEngineCopy[] = "QAbstractFileEngine::copy";
const char QAbstractFileEngineEntryList[] = "QAbstractFileEngine::entryList";
const char QAbstractFileEngineError[] = "QAbstractFileEngine::error";
const char QAbstractFileEngineErrorString[] = "QAbstractFileEngine::errorString";
const char QAbstractFileEngineFileFlags[] = "QAbstractFileEngine::fileFlags";
const char QAbstractFileEngineFileName[] = "QAbstractFileEngine::fileName";
const char QAbstractFileEngineFlush[] = "QAbstractFileEngine::flush";
const char QAbstractFileEngineHandle[] = "QAbstractFileEngine::handle";
const char QAbstractFileEngineIsRelativePath[] = "QAbstractFileEngine::isRelativePath";
const char QAbstractFileEngineIsSequential[] = "QAbstractFileEngine::isSequential";
const char QAbstractFileEngineLink[] = "QAbstractFileEngine::link";
const char QAbstractFileEngineMkdir[] = "QAbstractFileEngine::mkdir";
const char QAbstractFileEngineOpen[] = "QAbstractFileEngine::open";
const char QAbstractFileEngineOwner[] = "QAbstractFileEngine::owner";
const char QAbstractFileEngineOwnerId[] = "QAbstractFileEngine::ownerId";
const char QAbstractFileEnginePos[] = "QAbstractFileEngine::pos";
const char QAbstractFileEngineRead[] = "QAbstractFileEngine::read";
const char QAbstractFileEngineReadLine[] = "QAbstractFileEngine::readLine";
const char QAbstractFileEngineRemove[] = "QAbstractFileEngine::remove";
const char QAbstractFileEngineRename[] = "QAbstractFileEngine::rename";
const char QAbstractFileEngineRmdir[] = "QAbstractFileEngine::rmdir";
const char QAbstractFileEngineSeek[] = "QAbstractFileEngine::seek";
const char QAbstractFileEngineSetFileName[] = "QAbstractFileEngine::setFileName";
const char QAbstractFileEngineSetPermissions[] = "QAbstractFileEngine::setPermissions";
const char QAbstractFileEngineSetSize[] = "QAbstractFileEngine::setSize";
const char QAbstractFileEngineSize[] = "QAbstractFileEngine::size";
const char QAbstractFileEngineSupportsExtension[] = "QAbstractFileEngine::supportsExtension";
const char QAbstractFileEngineExtension[] = "QAbstractFileEngine::extension";
const char QAbstractFileEngineWrite[] = "QAbstractFileEngine::write";
} // namespace Protocol
} // namespace QInstaller
#endif // PROTOCOL_H

View File

@ -0,0 +1,160 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#include "remoteclient.h"
#include "protocol.h"
#include "remoteclient_p.h"
#include <QElapsedTimer>
#include <QUuid>
namespace QInstaller {
RemoteClient::RemoteClient()
: d_ptr(new RemoteClientPrivate(this))
{
Q_D(RemoteClient);
d->m_key = QUuid::createUuid().toString();
}
RemoteClient::~RemoteClient()
{
Q_D(RemoteClient);
d->m_quit = true;
}
RemoteClient &RemoteClient::instance()
{
static RemoteClient instance;
return instance;
}
QString RemoteClient::authorizationKey() const
{
Q_D(const RemoteClient);
return d->m_key;
}
void RemoteClient::setAuthorizationKey(const QString &key)
{
Q_D(RemoteClient);
if (d->m_serverStarted)
return;
d->m_key = key;
}
void RemoteClient::init(quint16 port, const QHostAddress &address, Mode mode)
{
Q_D(RemoteClient);
d->init(port, address, mode);
}
QTcpSocket *RemoteClient::connect() const
{
Q_D(const RemoteClient);
if (d->m_quit)
return 0;
int tries = 3;
QScopedPointer<QTcpSocket> socket(new QTcpSocket);
while ((tries > 0) && (!d->m_quit)) {
socket->connectToHost(d->m_address, d->m_port);
QElapsedTimer stopWatch;
stopWatch.start();
while ((socket->state() == QAbstractSocket::ConnectingState)
&& (stopWatch.elapsed() < 10000) && (!d->m_quit)) {
--tries;
qApp->processEvents();
continue;
}
if ((socket->state() != QAbstractSocket::ConnectedState) || d->m_quit)
return 0;
QDataStream stream;
stream.setDevice(socket.data());
stream << QString::fromLatin1(Protocol::Authorize) << d->m_key;
socket->waitForBytesWritten(-1);
if (!socket->bytesAvailable())
socket->waitForReadyRead(-1);
quint32 size; stream >> size;
bool authorized; stream >> authorized;
if (authorized && (!d->m_quit))
return socket.take();
}
return 0;
}
bool RemoteClient::isActive() const
{
Q_D(const RemoteClient);
return d->m_active;
}
void RemoteClient::setActive(bool active)
{
Q_D(RemoteClient);
d->m_active = active;
if (d->m_active) {
d->maybeStartServer();
d->m_active = d->m_serverStarted;
}
}
void RemoteClient::setStartServerCommand(const QString &command, StartAs startAs)
{
setStartServerCommand(command, QStringList(), startAs);
}
void RemoteClient::setStartServerCommand(const QString &command, const QStringList &arguments,
StartAs startAs)
{
Q_D(RemoteClient);
d->maybeStopServer();
d->m_serverCommand = command;
d->m_serverArguments = arguments;
d->m_startServerAsAdmin = startAs;
}
} // namespace QInstaller

View File

@ -0,0 +1,98 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#ifndef REMOTECLIENT_H
#define REMOTECLIENT_H
#include "installer_global.h"
#include <QObject>
QT_BEGIN_NAMESPACE
class QHostAddress;
class QTcpSocket;
QT_END_NAMESPACE
namespace QInstaller {
class RemoteClientPrivate;
class INSTALLER_EXPORT RemoteClient : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(RemoteClient)
Q_DECLARE_PRIVATE(RemoteClient)
public:
enum Mode {
Debug,
Release
};
enum StartAs {
User,
Administrator
};
static RemoteClient &instance();
QTcpSocket *connect() const;
void init(quint16 port, const QHostAddress &address, Mode mode);
QString authorizationKey() const;
void setAuthorizationKey(const QString &key);
bool isActive() const;
void setActive(bool active);
void setStartServerCommand(const QString &command, StartAs startAs);
void setStartServerCommand(const QString &command, const QStringList &arguments, StartAs start);
private:
RemoteClient();
~RemoteClient();
private:
QScopedPointer<RemoteClientPrivate> d_ptr;
};
} // namespace QInstaller
#endif // REMOTECLIENT_H

View File

@ -0,0 +1,240 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#ifndef REMOTECLIENT_P_H
#define REMOTECLIENT_P_H
#include "adminauthorization.h"
#include "messageboxhandler.h"
#include "protocol.h"
#include "remoteclient.h"
#include "utils.h"
#include <QCoreApplication>
#include <QElapsedTimer>
#include <QHostAddress>
#include <QMutex>
#include <QPointer>
#include <QTcpSocket>
#include <QThread>
#include <QTimer>
namespace QInstaller {
class KeepAliveObject : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(KeepAliveObject)
public:
KeepAliveObject(RemoteClient *client)
: m_timer(0)
, m_client(client)
{
}
public slots:
void run()
{
m_timer = new QTimer(this);
connect(m_timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
m_timer->start(1000);
}
private slots:
void onTimeout()
{
m_timer->stop();
if (!m_client)
return;
{
// Try to connect to the server. If we succeed the server side running watchdog gets
// restarted and the server keeps running for another 30 seconds.
QScopedPointer<QTcpSocket> socket(m_client->connect());
}
m_timer->start(1000);
}
private:
QTimer *m_timer;
QPointer<RemoteClient> m_client;
};
class RemoteClientPrivate
{
Q_DECLARE_PUBLIC(RemoteClient)
Q_DISABLE_COPY(RemoteClientPrivate)
public:
RemoteClientPrivate(RemoteClient *parent)
: q_ptr(parent)
, m_mutex(QMutex::Recursive)
, m_port(0)
, m_startServerAsAdmin(false)
, m_serverStarted(false)
, m_serverStarting(false)
, m_active(false)
, m_quit(false)
{
}
~RemoteClientPrivate()
{
m_thread.quit();
m_thread.wait();
}
void init(quint16 port, const QHostAddress &address, RemoteClient::Mode mode)
{
m_port = port;
m_mode = mode;
m_address = address;
if (m_mode == RemoteClient::Release) {
QObject *const object = new KeepAliveObject(q_ptr);
object->moveToThread(&m_thread);
QObject::connect(&m_thread, SIGNAL(finished()), object, SLOT(deleteLater()));
m_thread.start();
QTimer::singleShot(0, object, SLOT(run()));
} else if (mode == RemoteClient::Debug) {
m_active = true;
m_serverStarted = true;
m_key = QLatin1String(Protocol::DebugAuthorizationKey);
} else {
Q_ASSERT_X(false, Q_FUNC_INFO, "RemoteClient mode not set properly.");
}
}
void maybeStartServer() {
if (m_serverStarted || m_serverCommand.isEmpty())
return;
const QMutexLocker ml(&m_mutex);
if (m_serverStarted)
return;
m_serverStarting = true;
if (m_startServerAsAdmin) {
AdminAuthorization auth;
m_serverStarted = auth.authorize() && auth.execute(0, m_serverCommand, m_serverArguments);
if (!m_serverStarted) {
// something went wrong with authorizing, either user pressed cancel or entered
// wrong password
const QString fallback = m_serverCommand + QLatin1String(" ") + m_serverArguments
.join(QLatin1String(" "));
const QMessageBox::Button res =
MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(),
QObject::tr("Authorization Error"), QObject::tr("Could not get authorization."),
QObject::tr("Could not get authorization that is needed for continuing the "
"installation.\n Either abort the installation or use the fallback "
"solution by running\n%1\nas root and then clicking ok.").arg(fallback),
QMessageBox::Abort | QMessageBox::Ok, QMessageBox::Ok);
if (res == QMessageBox::Ok)
m_serverStarted = true;
}
} else {
m_serverStarted = QInstaller::startDetached(m_serverCommand, m_serverArguments,
QCoreApplication::applicationDirPath());
}
if (m_serverStarted) {
QElapsedTimer t;
t.start();
// 30 seconds ought to be enough for the app to start
while (m_serverStarting && m_serverStarted && t.elapsed() < 30000) {
Q_Q(RemoteClient);
QScopedPointer<QTcpSocket> socket(q->connect());
if (socket)
m_serverStarting = false;
}
}
m_serverStarting = false;
}
void maybeStopServer()
{
if (!m_serverStarted)
return;
const QMutexLocker ml(&m_mutex);
if (!m_serverStarted)
return;
Q_Q(RemoteClient);
QScopedPointer<QTcpSocket> socket(q->connect());
if (socket) {
QDataStream stream(socket.data());
stream << QString::fromLatin1(Protocol::Authorize);
stream << m_key;
stream << QString::fromLatin1(Protocol::Shutdown);
socket->flush();
}
m_serverStarted = false;
}
private:
RemoteClient *q_ptr;
QMutex m_mutex;
QHostAddress m_address;
quint16 m_port;
QString m_socket;
bool m_startServerAsAdmin;
bool m_serverStarted;
bool m_serverStarting;
bool m_active;
QString m_serverCommand;
QStringList m_serverArguments;
QString m_key;
QThread m_thread;
RemoteClient::Mode m_mode;
volatile bool m_quit;
};
} // namespace QInstaller
#endif // REMOTECLIENT_P_H

View File

@ -0,0 +1,519 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#include "remotefileengine.h"
#include "protocol.h"
#include "remoteclient.h"
#include <QTcpSocket>
namespace QInstaller {
// -- RemoteFileEngineHandler
QAbstractFileEngine* RemoteFileEngineHandler::create(const QString &fileName) const
{
if (!RemoteClient::instance().isActive())
return 0;
static QRegExp re(QLatin1String("^[a-z0-9]*://.*$"));
if (re.exactMatch(fileName)) // stuff like installer://
return 0;
if (fileName.isEmpty() || fileName.startsWith(QLatin1String(":")))
return 0; // empty filename or Qt resource
QScopedPointer<RemoteFileEngine> client(new RemoteFileEngine());
client->setFileName(fileName);
if (client->isConnectedToServer())
return client.take();
return 0;
}
// -- RemoteFileEngineIterator
class RemoteFileEngineIterator : public QAbstractFileEngineIterator
{
public:
RemoteFileEngineIterator(QDir::Filters filters, const QStringList &nameFilters,
const QStringList &files)
: QAbstractFileEngineIterator(filters, nameFilters)
, entries(files)
, index(-1)
{
}
/*!
\reimp
*/
bool hasNext() const
{
return index < entries.size() - 1;
}
/*!
\reimp
*/
QString next()
{
if (!hasNext())
return QString();
++index;
return currentFilePath();
}
/*!
\reimp
*/
QString currentFileName() const
{
return entries.at(index);
}
private:
const QStringList entries;
int index;
};
// -- RemoteFileEngine
RemoteFileEngine::RemoteFileEngine()
: RemoteObject(QLatin1String(Protocol::QAbstractFileEngine))
{
}
RemoteFileEngine::~RemoteFileEngine()
{
}
/*!
\reimp
*/
bool RemoteFileEngine::atEnd() const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer())
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineAtEnd));
return m_fileEngine.atEnd();
}
/*!
\reimp
*/
QAbstractFileEngine::Iterator* RemoteFileEngine::beginEntryList(QDir::Filters filters,
const QStringList &filterNames)
{
QStringList entries = entryList(filters, filterNames);
entries.removeAll(QString());
return new RemoteFileEngineIterator(filters, filterNames, entries);
}
/*!
\reimp
*/
bool RemoteFileEngine::caseSensitive() const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer())
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineCaseSensitive));
return m_fileEngine.caseSensitive();
}
/*!
\reimp
*/
bool RemoteFileEngine::close()
{
if (connectToServer())
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineClose));
return m_fileEngine.close();
}
/*!
\reimp
*/
bool RemoteFileEngine::copy(const QString &newName)
{
if (connectToServer())
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineCopy), newName);
return m_fileEngine.copy(newName);
}
/*!
\reimp
*/
QStringList RemoteFileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) {
return callRemoteMethod<QStringList>
(QString::fromLatin1(Protocol::QAbstractFileEngineEntryList), static_cast<int>(filters),
filterNames);
}
return m_fileEngine.entryList(filters, filterNames);
}
/*!
\reimp
*/
QFile::FileError RemoteFileEngine::error() const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) {
return static_cast<QFile::FileError>
(callRemoteMethod<int>(QString::fromLatin1(Protocol::QAbstractFileEngineError)));
}
return m_fileEngine.error();
}
/*!
\reimp
*/
QString RemoteFileEngine::errorString() const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer())
return callRemoteMethod<QString>(QString::fromLatin1(Protocol::QAbstractFileEngineErrorString));
return m_fileEngine.errorString();
}
/*!
\reimp
*/
bool RemoteFileEngine::extension(Extension extension, const ExtensionOption *eo, ExtensionReturn *er)
{
return false;
if (extension == UnMapExtension || extension == MapExtension)
return false;
if (connectToServer()) {
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineExtension),
static_cast<qint32> (extension));
}
return m_fileEngine.extension(extension, eo, er);
}
/*!
\reimp
*/
QAbstractFileEngine::FileFlags RemoteFileEngine::fileFlags(FileFlags type) const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) {
return static_cast<QAbstractFileEngine::FileFlags>
(callRemoteMethod<int>(QString::fromLatin1(Protocol::QAbstractFileEngineFileFlags),
static_cast<int>(type)));
}
return m_fileEngine.fileFlags(type);
}
/*!
\reimp
*/
QString RemoteFileEngine::fileName(FileName file) const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) {
return callRemoteMethod<QString>(QString::fromLatin1(Protocol::QAbstractFileEngineFileName),
static_cast<int>(file));
}
return m_fileEngine.fileName(file);
}
/*!
\reimp
*/
bool RemoteFileEngine::flush()
{
if (connectToServer())
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineFlush));
return m_fileEngine.flush();
}
/*!
\reimp
*/
int RemoteFileEngine::handle() const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer())
return callRemoteMethod<int>(QString::fromLatin1(Protocol::QAbstractFileEngineHandle));
return m_fileEngine.handle();
}
/*!
\reimp
*/
bool RemoteFileEngine::isRelativePath() const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer())
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineIsRelativePath));
return m_fileEngine.isRelativePath();
}
/*!
\reimp
*/
bool RemoteFileEngine::isSequential() const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer())
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineIsSequential));
return m_fileEngine.isSequential();
}
/*!
\reimp
*/
bool RemoteFileEngine::link(const QString &newName)
{
if (connectToServer()) {
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineLink),
newName);
}
return m_fileEngine.link(newName);
}
/*!
\reimp
*/
bool RemoteFileEngine::mkdir(const QString &dirName, bool createParentDirectories) const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) {
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineMkdir),
dirName, createParentDirectories);
}
return m_fileEngine.mkdir(dirName, createParentDirectories);
}
/*!
\reimp
*/
bool RemoteFileEngine::open(QIODevice::OpenMode mode)
{
if (connectToServer()) {
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineOpen),
static_cast<int>(mode));
}
return m_fileEngine.open(mode);
}
/*!
\reimp
*/
QString RemoteFileEngine::owner(FileOwner owner) const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) {
return callRemoteMethod<QString>(QString::fromLatin1(Protocol::QAbstractFileEngineOwner),
static_cast<int>(owner));
}
return m_fileEngine.owner(owner);
}
/*!
\reimp
*/
uint RemoteFileEngine::ownerId(FileOwner owner) const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) {
return callRemoteMethod<uint>(QString::fromLatin1(Protocol::QAbstractFileEngineOwnerId),
static_cast<int>(owner));
}
return m_fileEngine.ownerId(owner);
}
/*!
\reimp
*/
qint64 RemoteFileEngine::pos() const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer())
return callRemoteMethod<qint64>(QString::fromLatin1(Protocol::QAbstractFileEnginePos));
return m_fileEngine.pos();
}
/*!
\reimp
*/
bool RemoteFileEngine::remove()
{
if (connectToServer())
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineRemove));
return m_fileEngine.remove();
}
/*!
\reimp
*/
bool RemoteFileEngine::rename(const QString &newName)
{
if (connectToServer()) {
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineRename),
newName);
}
return m_fileEngine.rename(newName);
}
/*!
\reimp
*/
bool RemoteFileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) {
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineRmdir),
dirName, recurseParentDirectories);
}
return m_fileEngine.rmdir(dirName, recurseParentDirectories);
}
/*!
\reimp
*/
bool RemoteFileEngine::seek(qint64 offset)
{
if (connectToServer())
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineSeek), offset);
return m_fileEngine.seek(offset);
}
/*!
\reimp
*/
void RemoteFileEngine::setFileName(const QString &fileName)
{
if (connectToServer()) {
callRemoteMethod(QString::fromLatin1(Protocol::QAbstractFileEngineSetFileName), fileName,
dummy);
}
m_fileEngine.setFileName(fileName);
}
/*!
\reimp
*/
bool RemoteFileEngine::setPermissions(uint perms)
{
if (connectToServer()) {
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineSetPermissions),
perms);
}
return m_fileEngine.setPermissions(perms);
}
/*!
\reimp
*/
bool RemoteFileEngine::setSize(qint64 size)
{
if (connectToServer()) {
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineSetSize),
size);
}
return m_fileEngine.setSize(size);
}
/*!
\reimp
*/
qint64 RemoteFileEngine::size() const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer())
return callRemoteMethod<qint64>(QString::fromLatin1(Protocol::QAbstractFileEngineSize));
return m_fileEngine.size();
}
/*!
\reimp
*/
bool RemoteFileEngine::supportsExtension(Extension extension) const
{
return false;
if (extension == UnMapExtension || extension == MapExtension)
return false;
return m_fileEngine.supportsExtension(extension);
}
/*!
\reimp
*/
qint64 RemoteFileEngine::read(char *data, qint64 maxlen)
{
if (!connectToServer())
return m_fileEngine.read(data, maxlen);
QPair<qint64, QByteArray> result = callRemoteMethod<QPair<qint64, QByteArray> >
(QString::fromLatin1(Protocol::QAbstractFileEngineRead), maxlen);
if (result.first <= 0)
return result.first;
QDataStream dataStream(result.second);
dataStream.readRawData(data, result.first);
return result.first;
}
/*!
\reimp
*/
qint64 RemoteFileEngine::readLine(char *data, qint64 maxlen)
{
if (!connectToServer())
return m_fileEngine.readLine(data, maxlen);
QPair<qint64, QByteArray> result = callRemoteMethod<QPair<qint64, QByteArray> >
(QString::fromLatin1(Protocol::QAbstractFileEngineReadLine), maxlen);
if (result.first <= 0)
return result.first;
QDataStream dataStream(result.second);
dataStream.readRawData(data, result.first);
return result.first;
}
/*!
\reimp
*/
qint64 RemoteFileEngine::write(const char *data, qint64 len)
{
if (!connectToServer())
return m_fileEngine.write(data, len);
QByteArray ba(data, len);
return callRemoteMethod<qint64>(QString::fromLatin1(Protocol::QAbstractFileEngineWrite), ba);
}
} // namespace QInstaller

View File

@ -0,0 +1,109 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#ifndef REMOTEFILEENGINE_H
#define REMOTEFILEENGINE_H
#include "remoteobject.h"
#include <QtCore/private/qabstractfileengine_p.h>
#include <QtCore/private/qfsfileengine_p.h>
namespace QInstaller {
class INSTALLER_EXPORT RemoteFileEngineHandler : public QAbstractFileEngineHandler
{
Q_DISABLE_COPY(RemoteFileEngineHandler)
public:
RemoteFileEngineHandler() : QAbstractFileEngineHandler() {}
QAbstractFileEngine* create(const QString &fileName) const Q_DECL_OVERRIDE;
};
class RemoteFileEngine : public RemoteObject, public QAbstractFileEngine
{
Q_DISABLE_COPY(RemoteFileEngine)
public:
RemoteFileEngine();
~RemoteFileEngine();
bool atEnd() const;
Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames);
bool caseSensitive() const;
bool close();
bool copy(const QString &newName);
QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const;
QFile::FileError error() const;
QString errorString() const;
bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0);
FileFlags fileFlags(FileFlags type = FileInfoAll) const;
QString fileName(FileName file = DefaultName) const;
bool flush();
int handle() const;
bool isRelativePath() const;
bool isSequential() const;
bool link(const QString &newName);
bool mkdir(const QString &dirName, bool createParentDirectories) const;
bool open(QIODevice::OpenMode mode);
QString owner(FileOwner owner) const;
uint ownerId(FileOwner owner) const;
qint64 pos() const;
qint64 read(char *data, qint64 maxlen);
qint64 readLine(char *data, qint64 maxlen);
bool remove();
bool rename(const QString &newName);
bool rmdir(const QString &dirName, bool recurseParentDirectories) const;
bool seek(qint64 offset);
void setFileName(const QString &fileName);
bool setPermissions(uint perms);
bool setSize(qint64 size);
qint64 size() const;
bool supportsExtension(Extension extension) const;
qint64 write(const char *data, qint64 len);
private:
QFSFileEngine m_fileEngine;
};
} // namespace QInstaller
#endif // REMOTEFILEENGINE_H

View File

@ -0,0 +1,105 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#include "remoteobject.h"
#include "protocol.h"
#include "remoteclient.h"
namespace QInstaller {
RemoteObject::RemoteObject(const QString &wrappedType, QObject *parent)
: QObject(parent)
, m_socket(0)
, dummy(0)
, m_type(wrappedType)
{
Q_ASSERT_X(!m_type.isEmpty(), Q_FUNC_INFO, "The wrapped Qt type needs to be passed as "
"argument and cannot be empty.");
}
RemoteObject::~RemoteObject()
{
if (m_socket) {
m_stream << QString::fromLatin1(Protocol::Destroy) << m_type;
m_socket->waitForBytesWritten(-1);
}
}
bool RemoteObject::connectToServer(const QVariantList &arguments)
{
if (!RemoteClient::instance().isActive())
return false;
if (m_socket && (m_socket->state() == QAbstractSocket::ConnectedState))
return true;
if (m_socket)
m_socket->deleteLater();
m_socket = RemoteClient::instance().connect();
if (!m_socket)
return false;
m_stream.setDevice(m_socket);
m_stream << QString::fromLatin1(Protocol::Create) << m_type;
foreach (const QVariant &arg, arguments)
m_stream << arg;
m_socket->waitForBytesWritten(-1);
return true;
}
bool RemoteObject::isConnectedToServer() const
{
if ((!m_socket) || (!RemoteClient::instance().isActive()))
return false;
if (m_socket && (m_socket->state() == QAbstractSocket::ConnectedState))
return true;
return false;
}
void RemoteObject::callRemoteMethod(const QString &name)
{
writeData(name, dummy, dummy, dummy);
}
} // namespace QInstaller

View File

@ -0,0 +1,166 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#ifndef REMOTEOBJECT_H
#define REMOTEOBJECT_H
#include "errors.h"
#include "installer_global.h"
#include <QDataStream>
#include <QObject>
#include <QTcpSocket>
namespace QInstaller {
class INSTALLER_EXPORT RemoteObject : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(RemoteObject)
public:
RemoteObject(const QString &wrappedType, QObject *parent = 0);
virtual ~RemoteObject() = 0;
bool isConnectedToServer() const;
void callRemoteMethod(const QString &name);
template<typename T1, typename T2>
void callRemoteMethod(const QString &name, const T1 &arg, const T2 &arg2)
{
writeData(name, arg, arg2, dummy);
}
template<typename T1, typename T2, typename T3>
void callRemoteMethod(const QString &name, const T1 &arg, const T2 &arg2, const T3 & arg3)
{
writeData(name, arg, arg2, arg3);
}
template<typename T>
T callRemoteMethod(const QString &name) const
{
return callRemoteMethod<T>(name, dummy, dummy, dummy);
}
template<typename T, typename T1>
T callRemoteMethod(const QString &name, const T1 &arg) const
{
return callRemoteMethod<T>(name, arg, dummy, dummy);
}
template<typename T, typename T1, typename T2>
T callRemoteMethod(const QString &name, const T1 & arg, const T2 &arg2) const
{
return callRemoteMethod<T>(name, arg, arg2, dummy);
}
template<typename T, typename T1, typename T2, typename T3>
T callRemoteMethod(const QString &name, const T1 &arg, const T2 &arg2, const T3 &arg3) const
{
writeData(name, arg, arg2, arg3);
if (!m_socket->bytesAvailable())
m_socket->waitForReadyRead(-1);
quint32 size; m_stream >> size;
while (m_socket->bytesAvailable() < size) {
if (!m_socket->waitForReadyRead(30000)) {
throw Error(tr("Could not read all data after sending command: %1. "
"Bytes expected: %2, Bytes received: %3. Error: %3").arg(name).arg(size)
.arg(m_socket->bytesAvailable()).arg(m_socket->errorString()));
}
}
T result;
m_stream >> result;
return result;
}
protected:
bool connectToServer(const QVariantList &arguments = QVariantList());
// Use this structure to allow derived classes to manipulate the template
// function signature of the callRemoteMethod templates, since most of the
// generated functions will differ in return type rather given arguments.
struct Dummy {}; Dummy *dummy;
private:
template<typename T> bool isValueType(T) const
{
return true;
}
template<typename T> bool isValueType(T *dummy) const
{
// Force compiler error while passing anything different then Dummy* to the function.
// It really doesn't make sense to send any pointer over to the server, so bail early.
static_cast<Dummy*> (dummy);
return false;
}
template<typename T1, typename T2, typename T3>
void writeData(const QString &name, const T1 &arg, const T2 &arg2, const T3 &arg3) const
{
QByteArray data;
QDataStream out(&data, QIODevice::WriteOnly);
if (isValueType(arg))
out << arg;
if (isValueType(arg2))
out << arg2;
if (isValueType(arg3))
out << arg3;
m_stream << name;
m_stream << quint32(data.size());
m_stream << data;
m_socket->waitForBytesWritten(-1);
}
private:
QString m_type;
QTcpSocket *m_socket;
mutable QDataStream m_stream;
};
} // namespace QInstaller
#endif // REMOTEOBJECT_H

View File

@ -0,0 +1,122 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#include "remoteserver.h"
#include "protocol.h"
#include "remoteserver_p.h"
namespace QInstaller {
RemoteServer::RemoteServer(QObject *parent)
: QObject(parent)
, d_ptr(new RemoteServerPrivate(this))
{
}
RemoteServer::~RemoteServer()
{
Q_D(RemoteServer);
d->m_thread.quit();
d->m_thread.wait();
}
/*!
Starts the server. If started in debug mode, the watchdog that kills the server after
30 seconds without usage is not started. The authorization key is set to "DebugMode".
*/
void RemoteServer::start()
{
Q_D(RemoteServer);
if (d->m_tcpServer)
return;
d->m_tcpServer = new TcpServer(d->m_port, d->m_address, this);
d->m_tcpServer->moveToThread(&d->m_thread);
connect(&d->m_thread, SIGNAL(finished()), d->m_tcpServer, SLOT(deleteLater()));
connect (d->m_tcpServer, SIGNAL(newIncommingConnection()), this, SLOT(restartWatchdog()));
d->m_thread.start();
if (d->m_mode == RemoteServer::Release) {
connect(d->m_watchdog.data(), SIGNAL(timeout()), this, SLOT(deleteLater()));
d->m_watchdog->start();
} else {
setAuthorizationKey(QLatin1String(Protocol::DebugAuthorizationKey));
}
}
/*!
Returns the authorization key.
*/
QString RemoteServer::authorizationKey() const
{
Q_D(const RemoteServer);
return d->m_key;
}
/*!
Sets the authorization key \a authorizationKey this server is asking the clients for.
*/
void RemoteServer::setAuthorizationKey(const QString &authorizationKey)
{
Q_D(RemoteServer);
d->m_key = authorizationKey;
}
void RemoteServer::init(quint16 port, const QHostAddress &address, Mode mode)
{
Q_D(RemoteServer);
d->m_port = port;
d->m_address = address;
d->m_mode = mode;
}
/*!
Restarts the watchdog that tries to kill the server.
*/
void RemoteServer::restartWatchdog()
{
Q_D(RemoteServer);
if (d->m_watchdog)
d->m_watchdog->start();
}
} // namespace QInstaller

View File

@ -0,0 +1,87 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#ifndef REMOTESERVER_H
#define REMOTESERVER_H
#include "installer_global.h"
#include <QObject>
QT_BEGIN_NAMESPACE
class QHostAddress;
QT_END_NAMESPACE
namespace QInstaller {
class RemoteServerPrivate;
class INSTALLER_EXPORT RemoteServer : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(RemoteServer)
Q_DECLARE_PRIVATE(RemoteServer)
public:
enum Mode {
Debug,
Release
};
explicit RemoteServer(QObject *parent = 0);
~RemoteServer();
void start();
void init(quint16 port, const QHostAddress &address, Mode mode);
QString authorizationKey() const;
void setAuthorizationKey(const QString &key);
private slots:
void restartWatchdog();
private:
QScopedPointer<RemoteServerPrivate> d_ptr;
};
} // namespace QInstaller
#endif // REMOTESERVER_H

View File

@ -0,0 +1,123 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#ifndef REMOTESERVER_P_H
#define REMOTESERVER_P_H
#include "remoteserver.h"
#include "remoteserverconnection.h"
#include <QPointer>
#include <QTcpServer>
#include <QTimer>
namespace QInstaller {
class TcpServer : public QTcpServer
{
Q_OBJECT
Q_DISABLE_COPY(TcpServer)
public:
TcpServer(quint16 port, const QHostAddress &address, RemoteServer *server)
: QTcpServer(0)
, m_port(port)
, m_address(address)
, m_server(server)
{
listen(m_address, m_port);
}
~TcpServer() {
const QList<QThread *> threads = findChildren<QThread *>();
foreach (QThread *thread, threads) {
thread->quit();
thread->wait();
}
}
signals:
void newIncommingConnection();
private:
void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE {
QThread *const thread = new RemoteServerConnection(socketDescriptor, m_server);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
emit newIncommingConnection();
}
private:
quint16 m_port;
QHostAddress m_address;
QPointer<RemoteServer> m_server;
};
class RemoteServerPrivate
{
Q_DECLARE_PUBLIC(RemoteServer)
Q_DISABLE_COPY(RemoteServerPrivate)
public:
explicit RemoteServerPrivate(RemoteServer *server)
: q_ptr(server)
, m_tcpServer(0)
, m_watchdog(new QTimer)
{
m_watchdog->setInterval(30000);
m_watchdog->setSingleShot(true);
}
private:
RemoteServer *q_ptr;
TcpServer *m_tcpServer;
QString m_key;
quint16 m_port;
QThread m_thread;
QHostAddress m_address;
RemoteServer::Mode m_mode;
QScopedPointer<QTimer> m_watchdog;
};
} // namespace QInstaller
#endif // REMOTESERVER_P_H

View File

@ -0,0 +1,525 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#include "remoteserverconnection.h"
#include "errors.h"
#include "protocol.h"
#include "remoteserver.h"
#include "remoteserverconnection_p.h"
#include "utils.h"
#include <QSettings>
#include <QTcpSocket>
namespace QInstaller {
RemoteServerConnection::RemoteServerConnection(qintptr socketDescriptor, RemoteServer *parent)
: m_socketDescriptor(socketDescriptor)
, m_process(0)
, m_settings(0)
, m_engine(0)
, m_server(parent)
, m_signalReceiver(0)
{
}
void RemoteServerConnection::run()
{
QTcpSocket socket;
socket.setSocketDescriptor(m_socketDescriptor);
QDataStream stream;
stream.setDevice(&socket);
bool authorized = false;
while (socket.state() == QAbstractSocket::ConnectedState) {
// Use a polling approach here to kill the thread as soon as the connections
// closes. This seems to be related to the fact that the keep alive thread connects
// every second and immediately throws away the socket and therefor the connection.
if (!socket.bytesAvailable() && !socket.waitForReadyRead(250))
continue;
QString command;
stream >> command;
if (authorized && command == QLatin1String(Protocol::Shutdown)) {
// this is a graceful shutdown
socket.close();
if (m_server)
m_server->deleteLater();
return;
} else if (command == QLatin1String(Protocol::Authorize)) {
QString key;
stream >> key;
sendData(stream, (authorized = (m_server && (key == m_server->authorizationKey()))));
if (!authorized)
socket.close();
} else if (authorized) {
if (command.isEmpty())
continue;
if (command == QLatin1String(Protocol::Create)) {
QString type;
stream >> type;
if (type == QLatin1String(Protocol::QSettings)) {
QVariant application;
QVariant organization;
QVariant scope, format;
QVariant fileName;
stream >> application; stream >> organization; stream >> scope; stream >> format;
stream >> fileName;
if (m_settings)
m_settings->deleteLater();
if (fileName.toString().isEmpty()) {
m_settings = new QSettings(QSettings::Format(format.toInt()),
QSettings::Scope(scope.toInt()), organization.toString(), application
.toString());
} else {
m_settings = new QSettings(fileName.toString(), QSettings::NativeFormat);
}
} else if (type == QLatin1String(Protocol::QProcess)) {
if (m_process)
m_process->deleteLater();
m_process = new QProcess;
m_signalReceiver = new QProcessSignalReceiver(m_process);
} else if (type == QLatin1String(Protocol::QAbstractFileEngine)) {
if (m_engine)
delete m_engine;
m_engine = new QFSFileEngine;
}
continue;
}
if (command == QLatin1String(Protocol::Destroy)) {
QString type;
stream >> type;
if (type == QLatin1String(Protocol::QSettings)) {
m_settings->deleteLater();
m_settings = 0;
} else if (command == QLatin1String(Protocol::QProcess)) {
m_signalReceiver->m_receivedSignals.clear();
m_process->deleteLater();
m_process = 0;
} else if (command == QLatin1String(Protocol::QAbstractFileEngine)) {
delete m_engine;
m_engine = 0;
}
continue;
}
if (command == QLatin1String(Protocol::GetQProcessSignals)) {
if (m_signalReceiver) {
QMutexLocker _(&m_signalReceiver->m_lock);
sendData(stream, m_signalReceiver->m_receivedSignals);
m_signalReceiver->m_receivedSignals.clear();
}
continue;
}
if (command.startsWith(QLatin1String(Protocol::QProcess))) {
handleQProcess(command, stream);
} else if (command.startsWith(QLatin1String(Protocol::QSettings))) {
handleQSettings(command, stream);
} else if (command.startsWith(QLatin1String(Protocol::QAbstractFileEngine))) {
handleQFSFileEngine(command, stream);
} else {
qDebug() << "Unknown command:" << command;
}
} else {
// authorization failed, connection not wanted
socket.close();
qDebug() << "Unknown command:" << command;
return;
}
}
}
template <typename T>
void RemoteServerConnection::sendData(QDataStream &stream, const T &data)
{
QByteArray result;
QDataStream returnStream(&result, QIODevice::WriteOnly);
returnStream << data;
stream << static_cast<quint32> (result.size());
if (!result.isEmpty())
stream.writeRawData(result.data(), result.size());
}
void RemoteServerConnection::handleQProcess(const QString &command, QDataStream &stream)
{
quint32 size;
stream >> size;
while (stream.device()->bytesAvailable() < size) {
if (!stream.device()->waitForReadyRead(30000)) {
throw Error(tr("Could not read all data after sending command: %1. "
"Bytes expected: %2, Bytes received: %3. Error: %3").arg(command).arg(size)
.arg(stream.device()->bytesAvailable()).arg(stream.device()->errorString()));
}
}
QByteArray ba;
stream >> ba;
QDataStream data(ba);
if (command == QLatin1String(Protocol::QProcessCloseWriteChannel)) {
m_process->closeWriteChannel();
} else if (command == QLatin1String(Protocol::QProcessExitCode)) {
sendData(stream, m_process->exitCode());
} else if (command == QLatin1String(Protocol::QProcessExitStatus)) {
sendData(stream, static_cast<int> (m_process->exitStatus()));
} else if (command == QLatin1String(Protocol::QProcessKill)) {
m_process->kill();
} else if (command == QLatin1String(Protocol::QProcessReadAll)) {
sendData(stream, m_process->readAll());
} else if (command == QLatin1String(Protocol::QProcessReadAllStandardOutput)) {
sendData(stream, m_process->readAllStandardOutput());
} else if (command == QLatin1String(Protocol::QProcessReadAllStandardError)) {
sendData(stream, m_process->readAllStandardError());
} else if (command == QLatin1String(Protocol::QProcessStartDetached)) {
QString program;
QStringList arguments;
QString workingDirectory;
data >> program;
data >> arguments;
data >> workingDirectory;
qint64 pid = -1;
bool success = QInstaller::startDetached(program, arguments, workingDirectory, &pid);
sendData(stream, qMakePair< bool, qint64>(success, pid));
} else if (command == QLatin1String(Protocol::QProcessSetWorkingDirectory)) {
QString dir;
data >> dir;
m_process->setWorkingDirectory(dir);
} else if (command == QLatin1String(Protocol::QProcessSetEnvironment)) {
QStringList env;
data >> env;
m_process->setEnvironment(env);
} else if (command == QLatin1String(Protocol::QProcessEnvironment)) {
sendData(stream, m_process->environment());
} else if (command == QLatin1String(Protocol::QProcessStart3Arg)) {
QString program;
QStringList arguments;
int mode;
data >> program;
data >> arguments;
data >> mode;
m_process->start(program, arguments, static_cast<QIODevice::OpenMode> (mode));
} else if (command == QLatin1String(Protocol::QProcessStart2Arg)) {
QString program;
int mode;
data >> program;
data >> mode;
m_process->start(program, static_cast<QIODevice::OpenMode> (mode));
} else if (command == QLatin1String(Protocol::QProcessState)) {
sendData(stream, static_cast<int> (m_process->state()));
} else if (command == QLatin1String(Protocol::QProcessTerminate)) {
m_process->terminate();
} else if (command == QLatin1String(Protocol::QProcessWaitForFinished)) {
int msecs;
data >> msecs;
sendData(stream, m_process->waitForFinished(msecs));
} else if (command == QLatin1String(Protocol::QProcessWaitForStarted)) {
int msecs;
data >> msecs;
sendData(stream, m_process->waitForStarted(msecs));
} else if (command == QLatin1String(Protocol::QProcessWorkingDirectory)) {
sendData(stream, m_process->workingDirectory());
} else if (command == QLatin1String(Protocol::QProcessErrorString)) {
sendData(stream, m_process->errorString());
} else if (command == QLatin1String(Protocol::QProcessReadChannel)) {
sendData(stream, static_cast<int> (m_process->readChannel()));
} else if (command == QLatin1String(Protocol::QProcessSetReadChannel)) {
int processChannel;
data >> processChannel;
m_process->setReadChannel(static_cast<QProcess::ProcessChannel>(processChannel));
} else if (command == QLatin1String(Protocol::QProcessWrite)) {
QByteArray byteArray;
data >> byteArray;
sendData(stream, m_process->write(byteArray));
} else if (command == QLatin1String(Protocol::QProcessProcessChannelMode)) {
sendData(stream, static_cast<int> (m_process->processChannelMode()));
} else if (command == QLatin1String(Protocol::QProcessSetProcessChannelMode)) {
int processChannel;
data >> processChannel;
m_process->setProcessChannelMode(static_cast<QProcess::ProcessChannelMode>(processChannel));
}
#ifdef Q_OS_WIN
else if (command == QLatin1String(Protocol::QProcessSetNativeArguments)) {
QString arguments;
data >> arguments;
m_process->setNativeArguments(arguments);
}
#endif
else if (!command.isEmpty()) {
qDebug() << "Unknown QProcess command:" << command;
}
}
void RemoteServerConnection::handleQSettings(const QString &command, QDataStream &stream)
{
quint32 size;
stream >> size;
while (stream.device()->bytesAvailable() < size) {
if (!stream.device()->waitForReadyRead(30000)) {
throw Error(tr("Could not read all data after sending command: %1. "
"Bytes expected: %2, Bytes received: %3. Error: %3").arg(command).arg(size)
.arg(stream.device()->bytesAvailable()).arg(stream.device()->errorString()));
}
}
QByteArray ba;
stream >> ba;
QDataStream data(ba);
if (command == QLatin1String(Protocol::QSettingsAllKeys)) {
sendData(stream, m_settings->allKeys());
} else if (command == QLatin1String(Protocol::QSettingsBeginGroup)) {
QString prefix;
data >> prefix;
m_settings->beginGroup(prefix);
} else if (command == QLatin1String(Protocol::QSettingsBeginWriteArray)) {
QString prefix;
data >> prefix;
int size;
data >> size;
m_settings->beginWriteArray(prefix, size);
} else if (command == QLatin1String(Protocol::QSettingsBeginReadArray)) {
QString prefix;
data >> prefix;
sendData(stream, m_settings->beginReadArray(prefix));
} else if (command == QLatin1String(Protocol::QSettingsChildGroups)) {
sendData(stream, m_settings->childGroups());
} else if (command == QLatin1String(Protocol::QSettingsChildKeys)) {
sendData(stream, m_settings->childKeys());
} else if (command == QLatin1String(Protocol::QSettingsClear)) {
m_settings->clear();
} else if (command == QLatin1String(Protocol::QSettingsContains)) {
QString key;
data >> key;
sendData(stream, m_settings->contains(key));
} else if (command == QLatin1String(Protocol::QSettingsEndArray)) {
m_settings->endArray();
} else if (command == QLatin1String(Protocol::QSettingsEndGroup)) {
m_settings->endGroup();
} else if (command == QLatin1String(Protocol::QSettingsFallbacksEnabled)) {
sendData(stream, m_settings->fallbacksEnabled());
} else if (command == QLatin1String(Protocol::QSettingsFileName)) {
sendData(stream, m_settings->fileName());
} else if (command == QLatin1String(Protocol::QSettingsGroup)) {
sendData(stream, m_settings->group());
} else if (command == QLatin1String(Protocol::QSettingsIsWritable)) {
sendData(stream, m_settings->isWritable());
} else if (command == QLatin1String(Protocol::QSettingsRemove)) {
QString key;
data >> key;
m_settings->remove(key);
} else if (command == QLatin1String(Protocol::QSettingsSetArrayIndex)) {
int i;
data >> i;
m_settings->setArrayIndex(i);
} else if (command == QLatin1String(Protocol::QSettingsSetFallbacksEnabled)) {
bool b;
data >> b;
m_settings->setFallbacksEnabled(b);
} else if (command == QLatin1String(Protocol::QSettingsStatus)) {
sendData(stream, m_settings->status());
} else if (command == QLatin1String(Protocol::QSettingsSync)) {
m_settings->sync();
} else if (command == QLatin1String(Protocol::QSettingsSetValue)) {
QString key;
QVariant value;
data >> key;
data >> value;
m_settings->setValue(key, value);
} else if (command == QLatin1String(Protocol::QSettingsValue)) {
QString key;
QVariant defaultValue;
data >> key;
data >> defaultValue;
sendData(stream, m_settings->value(key, defaultValue));
} else if (command == QLatin1String(Protocol::QSettingsOrganizationName)) {
sendData(stream, m_settings->organizationName());
} else if (command == QLatin1String(Protocol::QSettingsApplicationName)) {
sendData(stream, m_settings->applicationName());
} else if (!command.isEmpty()) {
qDebug() << "Unknown QSettings command:" << command;
}
}
void RemoteServerConnection::handleQFSFileEngine(const QString &command, QDataStream &stream)
{
quint32 size;
stream >> size;
while (stream.device()->bytesAvailable() < size) {
if (!stream.device()->waitForReadyRead(30000)) {
throw Error(tr("Could not read all data after sending command: %1. "
"Bytes expected: %2, Bytes received: %3. Error: %3").arg(command).arg(size)
.arg(stream.device()->bytesAvailable()).arg(stream.device()->errorString()));
}
}
QByteArray ba;
stream >> ba;
QDataStream data(ba);
if (command == QLatin1String(Protocol::QAbstractFileEngineAtEnd)) {
sendData(stream, m_engine->atEnd());
} else if (command == QLatin1String(Protocol::QAbstractFileEngineCaseSensitive)) {
sendData(stream, m_engine->caseSensitive());
} else if (command == QLatin1String(Protocol::QAbstractFileEngineClose)) {
sendData(stream, m_engine->close());
} else if (command == QLatin1String(Protocol::QAbstractFileEngineCopy)) {
QString newName;
data >>newName;
sendData(stream, m_engine->copy(newName));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineEntryList)) {
int filters;
QStringList filterNames;
data >>filters;
data >>filterNames;
sendData(stream, m_engine->entryList(static_cast<QDir::Filters> (filters), filterNames));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineError)) {
sendData(stream, static_cast<int> (m_engine->error()));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineErrorString)) {
sendData(stream, m_engine->errorString());
}
else if (command == QLatin1String(Protocol::QAbstractFileEngineFileFlags)) {
int flags;
data >>flags;
sendData(stream,
static_cast<int>(m_engine->fileFlags(static_cast<QAbstractFileEngine::FileFlags>(flags))));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineFileName)) {
int file;
data >>file;
sendData(stream, m_engine->fileName(static_cast<QAbstractFileEngine::FileName> (file)));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineFlush)) {
sendData(stream, m_engine->flush());
} else if (command == QLatin1String(Protocol::QAbstractFileEngineHandle)) {
sendData(stream, m_engine->handle());
} else if (command == QLatin1String(Protocol::QAbstractFileEngineIsRelativePath)) {
sendData(stream, m_engine->isRelativePath());
} else if (command == QLatin1String(Protocol::QAbstractFileEngineIsSequential)) {
sendData(stream, m_engine->isSequential());
} else if (command == QLatin1String(Protocol::QAbstractFileEngineLink)) {
QString newName;
data >>newName;
sendData(stream, m_engine->link(newName));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineMkdir)) {
QString dirName;
bool createParentDirectories;
data >>dirName;
data >>createParentDirectories;
sendData(stream, m_engine->mkdir(dirName, createParentDirectories));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineOpen)) {
int openMode;
data >>openMode;
sendData(stream, m_engine->open(static_cast<QIODevice::OpenMode> (openMode)));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineOwner)) {
int owner;
data >>owner;
sendData(stream, m_engine->owner(static_cast<QAbstractFileEngine::FileOwner> (owner)));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineOwnerId)) {
int owner;
data >>owner;
sendData(stream, m_engine->ownerId(static_cast<QAbstractFileEngine::FileOwner> (owner)));
} else if (command == QLatin1String(Protocol::QAbstractFileEnginePos)) {
sendData(stream, m_engine->pos());
} else if (command == QLatin1String(Protocol::QAbstractFileEngineRead)) {
qint64 maxlen;
data >> maxlen;
QByteArray byteArray(maxlen, '\0');
const qint64 r = m_engine->read(byteArray.data(), maxlen);
sendData(stream, qMakePair<qint64, QByteArray>(r, byteArray));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineReadLine)) {
qint64 maxlen;
data >> maxlen;
QByteArray byteArray(maxlen, '\0');
const qint64 r = m_engine->readLine(byteArray.data(), maxlen);
sendData(stream, qMakePair<qint64, QByteArray>(r, byteArray));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineRemove)) {
sendData(stream, m_engine->remove());
} else if (command == QLatin1String(Protocol::QAbstractFileEngineRename)) {
QString newName;
data >>newName;
sendData(stream, m_engine->rename(newName));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineRmdir)) {
QString dirName;
bool recurseParentDirectories;
data >>dirName;
data >>recurseParentDirectories;
sendData(stream, m_engine->rmdir(dirName, recurseParentDirectories));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineSeek)) {
quint64 offset;
data >>offset;
sendData(stream, m_engine->seek(offset));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineSetFileName)) {
QString fileName;
data >>fileName;
m_engine->setFileName(fileName);
} else if (command == QLatin1String(Protocol::QAbstractFileEngineSetPermissions)) {
uint perms;
data >>perms;
sendData(stream, m_engine->setPermissions(perms));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineSetSize)) {
qint64 size;
data >>size;
sendData(stream, m_engine->setSize(size));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineSize)) {
sendData(stream, m_engine->size());
} else if (command == QLatin1String(Protocol::QAbstractFileEngineSupportsExtension)) {
// Implemented client side
} else if (command == QLatin1String(Protocol::QAbstractFileEngineExtension)) {
qint32 extension;
data >>extension;
sendData(stream, m_engine->extension(static_cast<QAbstractFileEngine::Extension> (extension)));
} else if (command == QLatin1String(Protocol::QAbstractFileEngineWrite)) {
QByteArray content;
data >> content;
sendData(stream, m_engine->write(content.data(), content.size()));
} else if (!command.isEmpty()) {
qDebug() << "Unknown QAbstractFileEngine command:" << command;
}
}
} // namespace QInstaller

View File

@ -0,0 +1,89 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#ifndef REMOTESERVERCONNECTION_H
#define REMOTESERVERCONNECTION_H
#include <QPointer>
#include <QThread>
#include <QtCore/private/qfsfileengine_p.h>
QT_BEGIN_NAMESPACE
class QProcess;
class QSettings;
QT_END_NAMESPACE
namespace QInstaller {
class QProcessSignalReceiver;
class RemoteServer;
class RemoteServerConnection : public QThread
{
Q_OBJECT
Q_DISABLE_COPY(RemoteServerConnection)
public:
RemoteServerConnection(qintptr socketDescriptor, RemoteServer *parent);
void run() Q_DECL_OVERRIDE;
private:
template <typename T>
void sendData(QDataStream &stream, const T &arg);
void handleQProcess(const QString &command, QDataStream &receivedStream);
void handleQSettings(const QString &command, QDataStream &receivedStream);
void handleQFSFileEngine(const QString &command, QDataStream &receivedStream);
private:
qintptr m_socketDescriptor;
QProcess *m_process;
QSettings *m_settings;
QFSFileEngine *m_engine;
QPointer<RemoteServer> m_server;
QProcessSignalReceiver *m_signalReceiver;
};
} // namespace QInstaller
#endif // REMOTESERVERCONNECTION_H

View File

@ -0,0 +1,140 @@
/**************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#ifndef REMOTESERVERCONNECTION_P_H
#define REMOTESERVERCONNECTION_P_H
#include "protocol.h"
#include <QMutex>
#include <QProcess>
#include <QVariant>
namespace QInstaller {
class QProcessSignalReceiver : public QObject
{
Q_OBJECT
friend class RemoteServerConnection;
private:
explicit QProcessSignalReceiver(QProcess *process)
: QObject(process)
{
connect(process, SIGNAL(bytesWritten(qint64)), SLOT(onBytesWritten(qint64)));
connect(process, SIGNAL(aboutToClose()), SLOT(onAboutToClose()));
connect(process, SIGNAL(readChannelFinished()), SLOT(onReadChannelFinished()));
connect(process, SIGNAL(error(QProcess::ProcessError)),
SLOT(onError(QProcess::ProcessError)));
connect(process, SIGNAL(readyReadStandardOutput()), SLOT(onReadyReadStandardOutput()));
connect(process, SIGNAL(readyReadStandardError()), SLOT(onReadyReadStandardError()));
connect(process, SIGNAL(finished(int, QProcess::ExitStatus)),
SLOT(onFinished(int, QProcess::ExitStatus)));
connect(process, SIGNAL(readyRead()), SLOT(onReadyRead()));
connect(process, SIGNAL(started()), SLOT(onStarted()));
connect(process, SIGNAL(stateChanged(QProcess::ProcessState)),
SLOT(onStateChanged(QProcess::ProcessState)));
}
private Q_SLOTS:
void onBytesWritten(qint64 count) {
QMutexLocker _(&m_lock);
m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalBytesWritten));
m_receivedSignals.append(count);
}
void onAboutToClose() {
QMutexLocker _(&m_lock);
m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalAboutToClose));
}
void onReadChannelFinished() {
QMutexLocker _(&m_lock);
m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalReadChannelFinished));
}
void onError(QProcess::ProcessError error) {
QMutexLocker _(&m_lock);
m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalError));
m_receivedSignals.append(static_cast<int> (error));
}
void onReadyReadStandardOutput() {
QMutexLocker _(&m_lock);
m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalReadyReadStandardOutput));
}
void onReadyReadStandardError() {
QMutexLocker _(&m_lock);
m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalReadyReadStandardError));
}
void onFinished(int exitCode, QProcess::ExitStatus exitStatus) {
QMutexLocker _(&m_lock);
m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalFinished));
m_receivedSignals.append(exitCode);
m_receivedSignals.append(static_cast<int> (exitStatus));
}
void onReadyRead() {
QMutexLocker _(&m_lock);
m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalReadyRead));
}
void onStarted() {
QMutexLocker _(&m_lock);
m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalStarted));
}
void onStateChanged(QProcess::ProcessState newState) {
QMutexLocker _(&m_lock);
m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalStateChanged));
m_receivedSignals.append(static_cast<int>(newState));
}
private:
QMutex m_lock;
QVariantList m_receivedSignals;
};
} // namespace QInstaller
#endif // REMOTESERVERCONNECTION_P_H

View File

@ -1,6 +1,6 @@
/**************************************************************************
**
** Copyright (C) 2012-2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
@ -84,6 +84,55 @@ void QInstaller::uiDetachedWait(int ms)
} while (timer.elapsed() < ms);
}
/*!
Starts the program \a program with the arguments \a arguments in a new process, and detaches
from it. Returns true on success; otherwise returns false. If the calling process exits, the
detached process will continue to live.
Note that arguments that contain spaces are not passed to the process as separate arguments.
Unix: The started process will run in its own session and act like a daemon.
Windows: Arguments that contain spaces are wrapped in quotes. The started process will run as
a regular standalone process.
The process will be started in the directory \a workingDirectory.
If the function is successful then \a *pid is set to the process identifier of the started
process.
Additional note: The difference in using this function over its equivalent from QProcess
appears on Windows. While this function will truly detach and not show a GUI
window for the started process, the QProcess version will.
*/
bool QInstaller::startDetached(const QString &program, const QStringList &arguments,
const QString &workingDirectory, qint64 *pid)
{
bool success = false;
#ifdef Q_OS_WIN
PROCESS_INFORMATION pinfo;
STARTUPINFOW startupInfo = { sizeof(STARTUPINFO), 0, 0, 0,
static_cast<ulong>(CW_USEDEFAULT), static_cast<ulong>(CW_USEDEFAULT),
static_cast<ulong>(CW_USEDEFAULT), static_cast<ulong>(CW_USEDEFAULT),
0, 0, 0, STARTF_USESHOWWINDOW, SW_HIDE, 0, 0, 0, 0, 0
}; // That's the difference over QProcess::startDetached(): STARTF_USESHOWWINDOW, SW_HIDE.
const QString commandline = QInstaller::createCommandline(program, arguments);
if (CreateProcessW(0, (wchar_t*) commandline.utf16(),
0, 0, false, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE,
0, workingDirectory.isEmpty() ? 0 : (wchar_t*) workingDirectory.utf16(),
&startupInfo, &pinfo)) {
success = true;
CloseHandle(pinfo.hThread);
CloseHandle(pinfo.hProcess);
if (pid)
*pid = pinfo.dwProcessId;
}
#else
success = QProcess::startDetached(program, arguments, workingDirectory, pid);
#endif
return success;
}
static bool verb = false;
void QInstaller::setVerbose(bool v)

View File

@ -1,6 +1,6 @@
/**************************************************************************
**
** Copyright (C) 2012-2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
@ -58,6 +58,8 @@ QT_END_NAMESPACE
namespace QInstaller {
void INSTALLER_EXPORT uiDetachedWait(int ms);
bool INSTALLER_EXPORT startDetached(const QString &program, const QStringList &arguments,
const QString &workingDirectory, qint64 *pid = 0);
QByteArray INSTALLER_EXPORT calculateHash(QIODevice *device, QCryptographicHash::Algorithm algo);
QByteArray INSTALLER_EXPORT calculateHash(const QString &path, QCryptographicHash::Algorithm algo);
@ -65,6 +67,7 @@ namespace QInstaller {
QString INSTALLER_EXPORT replaceVariables(const QHash<QString,QString> &vars, const QString &str);
QString INSTALLER_EXPORT replaceWindowsEnvironmentVariables(const QString &str);
QStringList INSTALLER_EXPORT parseCommandLineArgs(int argc, char **argv);
#ifdef Q_OS_WIN
QString createCommandline(const QString &program, const QStringList &arguments);
#endif