summaryrefslogtreecommitdiffstats
path: root/src/libs
diff options
context:
space:
mode:
authorkh1 <karsten.heimrich@digia.com>2014-06-03 10:59:40 +0200
committerKarsten Heimrich <karsten.heimrich@digia.com>2014-06-03 13:04:45 +0200
commit7c07130119722e2e0afcf423f23a449f93931dfa (patch)
treef82909d57cfec2da8e7377376d6dffac75b05aa4 /src/libs
parent00c6f94d1d6b7bce7c7339870bcad3d76b7cc390 (diff)
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>
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/installer/installer.pro20
-rw-r--r--src/libs/installer/installer_global.h2
-rw-r--r--src/libs/installer/protocol.h160
-rw-r--r--src/libs/installer/remoteclient.cpp160
-rw-r--r--src/libs/installer/remoteclient.h98
-rw-r--r--src/libs/installer/remoteclient_p.h240
-rw-r--r--src/libs/installer/remotefileengine.cpp519
-rw-r--r--src/libs/installer/remotefileengine.h109
-rw-r--r--src/libs/installer/remoteobject.cpp105
-rw-r--r--src/libs/installer/remoteobject.h166
-rw-r--r--src/libs/installer/remoteserver.cpp122
-rw-r--r--src/libs/installer/remoteserver.h87
-rw-r--r--src/libs/installer/remoteserver_p.h123
-rw-r--r--src/libs/installer/remoteserverconnection.cpp525
-rw-r--r--src/libs/installer/remoteserverconnection.h89
-rw-r--r--src/libs/installer/remoteserverconnection_p.h140
-rw-r--r--src/libs/installer/utils.cpp51
-rw-r--r--src/libs/installer/utils.h5
18 files changed, 2715 insertions, 6 deletions
diff --git a/src/libs/installer/installer.pro b/src/libs/installer/installer.pro
index 7a679d554..18b88dd3c 100644
--- a/src/libs/installer/installer.pro
+++ b/src/libs/installer/installer.pro
@@ -112,9 +112,18 @@ 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 \
+SOURCES += packagemanagercore.cpp \
packagemanagercore_p.cpp \
packagemanagergui.cpp \
binaryformat.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
diff --git a/src/libs/installer/installer_global.h b/src/libs/installer/installer_global.h
index 635dbcf46..e615eefc6 100644
--- a/src/libs/installer/installer_global.h
+++ b/src/libs/installer/installer_global.h
@@ -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.
diff --git a/src/libs/installer/protocol.h b/src/libs/installer/protocol.h
new file mode 100644
index 000000000..cc084c221
--- /dev/null
+++ b/src/libs/installer/protocol.h
@@ -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
diff --git a/src/libs/installer/remoteclient.cpp b/src/libs/installer/remoteclient.cpp
new file mode 100644
index 000000000..60ccb3409
--- /dev/null
+++ b/src/libs/installer/remoteclient.cpp
@@ -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
diff --git a/src/libs/installer/remoteclient.h b/src/libs/installer/remoteclient.h
new file mode 100644
index 000000000..ff92a3dda
--- /dev/null
+++ b/src/libs/installer/remoteclient.h
@@ -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
diff --git a/src/libs/installer/remoteclient_p.h b/src/libs/installer/remoteclient_p.h
new file mode 100644
index 000000000..5f7dc0bea
--- /dev/null
+++ b/src/libs/installer/remoteclient_p.h
@@ -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
diff --git a/src/libs/installer/remotefileengine.cpp b/src/libs/installer/remotefileengine.cpp
new file mode 100644
index 000000000..776f8301e
--- /dev/null
+++ b/src/libs/installer/remotefileengine.cpp
@@ -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
diff --git a/src/libs/installer/remotefileengine.h b/src/libs/installer/remotefileengine.h
new file mode 100644
index 000000000..3e57d963a
--- /dev/null
+++ b/src/libs/installer/remotefileengine.h
@@ -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
diff --git a/src/libs/installer/remoteobject.cpp b/src/libs/installer/remoteobject.cpp
new file mode 100644
index 000000000..2c1aa275a
--- /dev/null
+++ b/src/libs/installer/remoteobject.cpp
@@ -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
diff --git a/src/libs/installer/remoteobject.h b/src/libs/installer/remoteobject.h
new file mode 100644
index 000000000..4a0a21731
--- /dev/null
+++ b/src/libs/installer/remoteobject.h
@@ -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
diff --git a/src/libs/installer/remoteserver.cpp b/src/libs/installer/remoteserver.cpp
new file mode 100644
index 000000000..2bd74c03a
--- /dev/null
+++ b/src/libs/installer/remoteserver.cpp
@@ -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
diff --git a/src/libs/installer/remoteserver.h b/src/libs/installer/remoteserver.h
new file mode 100644
index 000000000..e1158dd68
--- /dev/null
+++ b/src/libs/installer/remoteserver.h
@@ -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
diff --git a/src/libs/installer/remoteserver_p.h b/src/libs/installer/remoteserver_p.h
new file mode 100644
index 000000000..72ee0267c
--- /dev/null
+++ b/src/libs/installer/remoteserver_p.h
@@ -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
diff --git a/src/libs/installer/remoteserverconnection.cpp b/src/libs/installer/remoteserverconnection.cpp
new file mode 100644
index 000000000..a3c3eda51
--- /dev/null
+++ b/src/libs/installer/remoteserverconnection.cpp
@@ -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
diff --git a/src/libs/installer/remoteserverconnection.h b/src/libs/installer/remoteserverconnection.h
new file mode 100644
index 000000000..65f247178
--- /dev/null
+++ b/src/libs/installer/remoteserverconnection.h
@@ -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
diff --git a/src/libs/installer/remoteserverconnection_p.h b/src/libs/installer/remoteserverconnection_p.h
new file mode 100644
index 000000000..6c975377e
--- /dev/null
+++ b/src/libs/installer/remoteserverconnection_p.h
@@ -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
diff --git a/src/libs/installer/utils.cpp b/src/libs/installer/utils.cpp
index 61af9ae27..b348da8c3 100644
--- a/src/libs/installer/utils.cpp
+++ b/src/libs/installer/utils.cpp
@@ -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)
diff --git a/src/libs/installer/utils.h b/src/libs/installer/utils.h
index 2bc7a1801..879b29afc 100644
--- a/src/libs/installer/utils.h
+++ b/src/libs/installer/utils.h
@@ -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