forked from qt-creator/qt-creator
iostool: support for qml debug and remote port forwarding
Change-Id: Id45cc17df1cb941ad0e09ecb6d7936dacac24755 Reviewed-by: Fawzi Mohamed <fawzi.mohamed@digia.com>
This commit is contained in:
@@ -36,7 +36,9 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
#include <QRegExp>
|
||||||
#include <mach/error.h>
|
#include <mach/error.h>
|
||||||
|
|
||||||
/* // annoying to import, do without
|
/* // annoying to import, do without
|
||||||
#if QT_VERSION < 0x050000
|
#if QT_VERSION < 0x050000
|
||||||
#include <private/qcore_mac_p.h>
|
#include <private/qcore_mac_p.h>
|
||||||
@@ -60,8 +62,12 @@
|
|||||||
#include "MobileDevice.h"
|
#include "MobileDevice.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// avoid utils dependency
|
||||||
|
#define QTC_OVERRIDE override
|
||||||
|
|
||||||
static const bool debugGdbServer = false;
|
static const bool debugGdbServer = false;
|
||||||
static const bool debugAll = false;
|
static const bool debugAll = false;
|
||||||
|
static const bool verbose = true;
|
||||||
|
|
||||||
// ------- MobileDeviceLib interface --------
|
// ------- MobileDeviceLib interface --------
|
||||||
namespace {
|
namespace {
|
||||||
@@ -126,6 +132,8 @@ typedef am_res_t (MDEV_API *AMDeviceUninstallApplicationPtr)(ServiceSocket, CFSt
|
|||||||
AMDeviceInstallApplicationCallback,
|
AMDeviceInstallApplicationCallback,
|
||||||
void*);
|
void*);
|
||||||
typedef am_res_t (MDEV_API *AMDeviceLookupApplicationsPtr)(AMDeviceRef, CFDictionaryRef, CFDictionaryRef *);
|
typedef am_res_t (MDEV_API *AMDeviceLookupApplicationsPtr)(AMDeviceRef, CFDictionaryRef, CFDictionaryRef *);
|
||||||
|
typedef am_res_t (MDEV_API *USBMuxConnectByPortPtr)(unsigned int, int, ServiceSocket*);
|
||||||
|
|
||||||
} // extern C
|
} // extern C
|
||||||
|
|
||||||
QString CFStringRef2QString(CFStringRef s)
|
QString CFStringRef2QString(CFStringRef s)
|
||||||
@@ -205,6 +213,7 @@ public :
|
|||||||
AMDeviceInstallApplicationCallback,
|
AMDeviceInstallApplicationCallback,
|
||||||
void*);
|
void*);
|
||||||
am_res_t deviceLookupApplications(AMDeviceRef, CFDictionaryRef, CFDictionaryRef *);
|
am_res_t deviceLookupApplications(AMDeviceRef, CFDictionaryRef, CFDictionaryRef *);
|
||||||
|
am_res_t connectByPort(unsigned int connectionId, int port, ServiceSocket *resFd);
|
||||||
|
|
||||||
void addError(const QString &msg);
|
void addError(const QString &msg);
|
||||||
void addError(const char *msg);
|
void addError(const char *msg);
|
||||||
@@ -231,6 +240,7 @@ private:
|
|||||||
AMDeviceInstallApplicationPtr m_AMDeviceInstallApplication;
|
AMDeviceInstallApplicationPtr m_AMDeviceInstallApplication;
|
||||||
AMDeviceUninstallApplicationPtr m_AMDeviceUninstallApplication;
|
AMDeviceUninstallApplicationPtr m_AMDeviceUninstallApplication;
|
||||||
AMDeviceLookupApplicationsPtr m_AMDeviceLookupApplications;
|
AMDeviceLookupApplicationsPtr m_AMDeviceLookupApplications;
|
||||||
|
USBMuxConnectByPortPtr m_USBMuxConnectByPort;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -244,7 +254,8 @@ public:
|
|||||||
void *userData;
|
void *userData;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CommandSession {
|
class CommandSession : public DeviceSession
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~CommandSession();
|
virtual ~CommandSession();
|
||||||
explicit CommandSession(const QString &deviceId);
|
explicit CommandSession(const QString &deviceId);
|
||||||
@@ -262,6 +273,8 @@ public:
|
|||||||
bool startService(const QString &service, ServiceSocket &fd);
|
bool startService(const QString &service, ServiceSocket &fd);
|
||||||
void stopService(ServiceSocket fd);
|
void stopService(ServiceSocket fd);
|
||||||
void startDeviceLookup(int timeout);
|
void startDeviceLookup(int timeout);
|
||||||
|
bool connectToPort(quint16 port, ServiceSocket *fd) QTC_OVERRIDE;
|
||||||
|
int qmljsDebugPort() const QTC_OVERRIDE;
|
||||||
void addError(const QString &msg);
|
void addError(const QString &msg);
|
||||||
bool writeAll(ServiceSocket fd, const char *cmd, qptrdiff len = -1);
|
bool writeAll(ServiceSocket fd, const char *cmd, qptrdiff len = -1);
|
||||||
bool sendGdbCommand(ServiceSocket fd, const char *cmd, qptrdiff len = -1);
|
bool sendGdbCommand(ServiceSocket fd, const char *cmd, qptrdiff len = -1);
|
||||||
@@ -271,7 +284,6 @@ public:
|
|||||||
|
|
||||||
MobileDeviceLib *lib();
|
MobileDeviceLib *lib();
|
||||||
|
|
||||||
QString deviceId;
|
|
||||||
AMDeviceRef device;
|
AMDeviceRef device;
|
||||||
int progressBase;
|
int progressBase;
|
||||||
int unexpectedChars;
|
int unexpectedChars;
|
||||||
@@ -300,7 +312,7 @@ public:
|
|||||||
void didTransferApp(const QString &bundlePath, const QString &deviceId,
|
void didTransferApp(const QString &bundlePath, const QString &deviceId,
|
||||||
Ios::IosDeviceManager::OpStatus status);
|
Ios::IosDeviceManager::OpStatus status);
|
||||||
void didStartApp(const QString &bundlePath, const QString &deviceId,
|
void didStartApp(const QString &bundlePath, const QString &deviceId,
|
||||||
Ios::IosDeviceManager::OpStatus status, int fd);
|
Ios::IosDeviceManager::OpStatus status, int gdbFd, DeviceSession *deviceSession);
|
||||||
void isTransferringApp(const QString &bundlePath, const QString &deviceId, int progress,
|
void isTransferringApp(const QString &bundlePath, const QString &deviceId, int progress,
|
||||||
const QString &info);
|
const QString &info);
|
||||||
void deviceWithId(QString deviceId, int timeout, DeviceAvailableCallback callback, void *userData);
|
void deviceWithId(QString deviceId, int timeout, DeviceAvailableCallback callback, void *userData);
|
||||||
@@ -334,6 +346,7 @@ public:
|
|||||||
void deviceCallbackReturned();
|
void deviceCallbackReturned();
|
||||||
bool installApp();
|
bool installApp();
|
||||||
bool runApp();
|
bool runApp();
|
||||||
|
int qmljsDebugPort() const QTC_OVERRIDE;
|
||||||
am_res_t appTransferCallback(CFDictionaryRef dict);
|
am_res_t appTransferCallback(CFDictionaryRef dict);
|
||||||
am_res_t appInstallCallback(CFDictionaryRef dict);
|
am_res_t appInstallCallback(CFDictionaryRef dict);
|
||||||
void reportProgress2(int progress, const QString &status);
|
void reportProgress2(int progress, const QString &status);
|
||||||
@@ -342,7 +355,18 @@ public:
|
|||||||
QString commandName();
|
QString commandName();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
}
|
||||||
|
|
||||||
|
DeviceSession::DeviceSession(const QString &deviceId) :
|
||||||
|
deviceId(deviceId)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceSession::~DeviceSession()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// namespace Internal
|
||||||
} // namespace Ios
|
} // namespace Ios
|
||||||
|
|
||||||
|
|
||||||
@@ -556,9 +580,11 @@ void IosDeviceManagerPrivate::didTransferApp(const QString &bundlePath, const QS
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IosDeviceManagerPrivate::didStartApp(const QString &bundlePath, const QString &deviceId,
|
void IosDeviceManagerPrivate::didStartApp(const QString &bundlePath, const QString &deviceId,
|
||||||
IosDeviceManager::OpStatus status, int fd)
|
IosDeviceManager::OpStatus status, int gdbFd,
|
||||||
|
DeviceSession *deviceSession)
|
||||||
{
|
{
|
||||||
emit IosDeviceManagerPrivate::instance()->q->didStartApp(bundlePath, deviceId, status, fd);
|
emit IosDeviceManagerPrivate::instance()->q->didStartApp(bundlePath, deviceId, status, gdbFd,
|
||||||
|
deviceSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IosDeviceManagerPrivate::isTransferringApp(const QString &bundlePath, const QString &deviceId,
|
void IosDeviceManagerPrivate::isTransferringApp(const QString &bundlePath, const QString &deviceId,
|
||||||
@@ -709,7 +735,7 @@ int IosDeviceManagerPrivate::processGdbServer(int fd)
|
|||||||
|
|
||||||
// ------- ConnectSession implementation --------
|
// ------- ConnectSession implementation --------
|
||||||
|
|
||||||
CommandSession::CommandSession(const QString &deviceId) : deviceId(deviceId), device(0),
|
CommandSession::CommandSession(const QString &deviceId) : DeviceSession(deviceId), device(0),
|
||||||
progressBase(0), unexpectedChars(0), aknowledge(true)
|
progressBase(0), unexpectedChars(0), aknowledge(true)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@@ -777,6 +803,32 @@ bool CommandSession::startService(const QString &serviceName, ServiceSocket &fd)
|
|||||||
return !failure;
|
return !failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CommandSession::connectToPort(quint16 port, ServiceSocket *fd)
|
||||||
|
{
|
||||||
|
if (!fd)
|
||||||
|
return false;
|
||||||
|
bool failure = false;
|
||||||
|
*fd = 0;
|
||||||
|
ServiceSocket fileDescriptor;
|
||||||
|
if (!connectDevice())
|
||||||
|
return false;
|
||||||
|
if (am_res_t error = lib()->connectByPort(lib()->deviceGetConnectionID(device), htons(port), &fileDescriptor)) {
|
||||||
|
addError(QString::fromLatin1("connectByPort on device %1 port %2 failed, AMDeviceStartService returned %3")
|
||||||
|
.arg(deviceId).arg(port).arg(error));
|
||||||
|
failure = true;
|
||||||
|
*fd = -1;
|
||||||
|
} else {
|
||||||
|
*fd = fileDescriptor;
|
||||||
|
}
|
||||||
|
disconnectDevice();
|
||||||
|
return !failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CommandSession::qmljsDebugPort() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void CommandSession::stopService(ServiceSocket fd)
|
void CommandSession::stopService(ServiceSocket fd)
|
||||||
{
|
{
|
||||||
// would be close socket on windows
|
// would be close socket on windows
|
||||||
@@ -791,7 +843,7 @@ void CommandSession::startDeviceLookup(int timeout)
|
|||||||
|
|
||||||
void CommandSession::addError(const QString &msg)
|
void CommandSession::addError(const QString &msg)
|
||||||
{
|
{
|
||||||
if (debugAll)
|
if (verbose)
|
||||||
qDebug() << "CommandSession ERROR: " << msg;
|
qDebug() << "CommandSession ERROR: " << msg;
|
||||||
IosDeviceManagerPrivate::instance()->addError(commandName() + msg);
|
IosDeviceManagerPrivate::instance()->addError(commandName() + msg);
|
||||||
}
|
}
|
||||||
@@ -985,7 +1037,7 @@ bool CommandSession::expectGdbReply(ServiceSocket gdbFd, QByteArray expected)
|
|||||||
{
|
{
|
||||||
QByteArray repl = readGdbReply(gdbFd);
|
QByteArray repl = readGdbReply(gdbFd);
|
||||||
if (repl != expected) {
|
if (repl != expected) {
|
||||||
addError(QString::fromLatin1("Unexpected reply: %1 (%2) vs %3 (%3)")
|
addError(QString::fromLatin1("Unexpected reply: %1 (%2) vs %3 (%4)")
|
||||||
.arg(QString::fromLocal8Bit(repl.constData(), repl.size()))
|
.arg(QString::fromLocal8Bit(repl.constData(), repl.size()))
|
||||||
.arg(QString::fromLatin1(repl.toHex().constData(), 2*repl.size()))
|
.arg(QString::fromLatin1(repl.toHex().constData(), 2*repl.size()))
|
||||||
.arg(QString::fromLocal8Bit(expected.constData(), expected.size()))
|
.arg(QString::fromLocal8Bit(expected.constData(), expected.size()))
|
||||||
@@ -1090,6 +1142,20 @@ void AppOpSession::deviceCallbackReturned()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AppOpSession::qmljsDebugPort() const
|
||||||
|
{
|
||||||
|
QRegExp qmlPortRe = QRegExp(QLatin1String("-qmljsdebugger=port:([0-9]+)"));
|
||||||
|
foreach (const QString &arg, extraArgs) {
|
||||||
|
if (qmlPortRe.indexIn(arg) == 0) {
|
||||||
|
bool ok;
|
||||||
|
int res = qmlPortRe.cap(1).toInt(&ok);
|
||||||
|
if (ok && res >0 && res <= 0xFFFF)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool AppOpSession::runApp()
|
bool AppOpSession::runApp()
|
||||||
{
|
{
|
||||||
bool failure = (device == 0);
|
bool failure = (device == 0);
|
||||||
@@ -1128,7 +1194,7 @@ bool AppOpSession::runApp()
|
|||||||
}
|
}
|
||||||
IosDeviceManagerPrivate::instance()->didStartApp(
|
IosDeviceManagerPrivate::instance()->didStartApp(
|
||||||
bundlePath, deviceId,
|
bundlePath, deviceId,
|
||||||
(failure ? IosDeviceManager::Failure : IosDeviceManager::Success), gdbFd);
|
(failure ? IosDeviceManager::Failure : IosDeviceManager::Success), gdbFd, this);
|
||||||
return !failure;
|
return !failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1326,6 +1392,7 @@ bool MobileDeviceLib::load()
|
|||||||
m_AMDeviceInstallApplication = &AMDeviceInstallApplication;
|
m_AMDeviceInstallApplication = &AMDeviceInstallApplication;
|
||||||
//m_AMDeviceUninstallApplication = &AMDeviceUninstallApplication;
|
//m_AMDeviceUninstallApplication = &AMDeviceUninstallApplication;
|
||||||
//m_AMDeviceLookupApplications = &AMDeviceLookupApplications;
|
//m_AMDeviceLookupApplications = &AMDeviceLookupApplications;
|
||||||
|
m_USBMuxConnectByPort = &USBMuxConnectByPort;
|
||||||
#else
|
#else
|
||||||
QLibrary *libAppleFSCompression = new QLibrary(QLatin1String("/System/Library/PrivateFrameworks/AppleFSCompression.framework/AppleFSCompression"));
|
QLibrary *libAppleFSCompression = new QLibrary(QLatin1String("/System/Library/PrivateFrameworks/AppleFSCompression.framework/AppleFSCompression"));
|
||||||
if (!libAppleFSCompression->load())
|
if (!libAppleFSCompression->load())
|
||||||
@@ -1395,6 +1462,9 @@ bool MobileDeviceLib::load()
|
|||||||
m_AMDeviceLookupApplications = reinterpret_cast<AMDeviceLookupApplicationsPtr>(lib.resolve("AMDeviceLookupApplications"));
|
m_AMDeviceLookupApplications = reinterpret_cast<AMDeviceLookupApplicationsPtr>(lib.resolve("AMDeviceLookupApplications"));
|
||||||
if (m_AMDeviceLookupApplications == 0)
|
if (m_AMDeviceLookupApplications == 0)
|
||||||
addError("MobileDeviceLib does not define AMDeviceLookupApplications");
|
addError("MobileDeviceLib does not define AMDeviceLookupApplications");
|
||||||
|
m_USBMuxConnectByPort = reinterpret_cast<USBMuxConnectByPortPtr>(lib.resolve("USBMuxConnectByPort"));
|
||||||
|
if (m_USBMuxConnectByPort == 0)
|
||||||
|
addError("MobileDeviceLib does not define USBMuxConnectByPort");
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1557,6 +1627,13 @@ am_res_t MobileDeviceLib::deviceLookupApplications(AMDeviceRef device, CFDiction
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
am_res_t MobileDeviceLib::connectByPort(unsigned int connectionId, int port, ServiceSocket *resFd)
|
||||||
|
{
|
||||||
|
if (m_USBMuxConnectByPort)
|
||||||
|
return m_USBMuxConnectByPort(connectionId, port, resFd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void MobileDeviceLib::addError(const QString &msg)
|
void MobileDeviceLib::addError(const QString &msg)
|
||||||
{
|
{
|
||||||
qDebug() << "MobileDeviceLib ERROR:" << msg;
|
qDebug() << "MobileDeviceLib ERROR:" << msg;
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ class DevInfoSession;
|
|||||||
class IosDeviceManagerPrivate;
|
class IosDeviceManagerPrivate;
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|
||||||
|
typedef unsigned int ServiceSocket;
|
||||||
|
|
||||||
|
class DeviceSession;
|
||||||
|
|
||||||
class IosDeviceManager : public QObject
|
class IosDeviceManager : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -77,7 +81,8 @@ signals:
|
|||||||
void didTransferApp(const QString &bundlePath, const QString &deviceId,
|
void didTransferApp(const QString &bundlePath, const QString &deviceId,
|
||||||
Ios::IosDeviceManager::OpStatus status);
|
Ios::IosDeviceManager::OpStatus status);
|
||||||
void didStartApp(const QString &bundlePath, const QString &deviceId,
|
void didStartApp(const QString &bundlePath, const QString &deviceId,
|
||||||
Ios::IosDeviceManager::OpStatus status, int gdbFd);
|
Ios::IosDeviceManager::OpStatus status, int gdbFd,
|
||||||
|
Ios::DeviceSession *deviceSession);
|
||||||
void deviceInfo(const QString &deviceId, const Ios::IosDeviceManager::Dict &info);
|
void deviceInfo(const QString &deviceId, const Ios::IosDeviceManager::Dict &info);
|
||||||
void appOutput(const QString &output);
|
void appOutput(const QString &output);
|
||||||
void errorMsg(const QString &msg);
|
void errorMsg(const QString &msg);
|
||||||
@@ -90,6 +95,15 @@ private:
|
|||||||
Internal::IosDeviceManagerPrivate *d;
|
Internal::IosDeviceManagerPrivate *d;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DeviceSession {
|
||||||
|
public:
|
||||||
|
DeviceSession(const QString &deviceId);
|
||||||
|
virtual ~DeviceSession();
|
||||||
|
QString deviceId;
|
||||||
|
virtual int qmljsDebugPort() const = 0;
|
||||||
|
virtual bool connectToPort(quint16 port, ServiceSocket *fd) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Ios
|
} // namespace Ios
|
||||||
|
|
||||||
#endif // IOSMANAGER_H
|
#endif // IOSMANAGER_H
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
#include "iosdevicemanager.h"
|
||||||
|
|
||||||
#include <qglobal.h>
|
#include <qglobal.h>
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@@ -41,8 +43,12 @@
|
|||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
#include <QSocketNotifier>
|
#include <QSocketNotifier>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QMutexLocker>
|
||||||
|
|
||||||
#include "iosdevicemanager.h"
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@@ -53,9 +59,111 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const bool debugGdbEchoServer = false;
|
// avoid utils dependency
|
||||||
|
#define QTC_OVERRIDE override
|
||||||
|
#define QTC_CHECK(cond) if (cond) {} else { qWarning() << "assert failed " << #cond << " " \
|
||||||
|
<< __FILE__ << ":" << __LINE__; } do {} while (0)
|
||||||
|
|
||||||
class IosTool: public QObject {
|
static bool echoRelays = false;
|
||||||
|
|
||||||
|
class IosTool;
|
||||||
|
class RelayServer;
|
||||||
|
class GenericRelayServer;
|
||||||
|
|
||||||
|
class Relayer: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
Relayer(RelayServer *parent, QTcpSocket *clientSocket);
|
||||||
|
~Relayer();
|
||||||
|
void setClientSocket(QTcpSocket *clientSocket);
|
||||||
|
bool startRelay(int serverFileDescriptor);
|
||||||
|
public slots:
|
||||||
|
void handleSocketHasData(int socket);
|
||||||
|
void handleClientHasData();
|
||||||
|
void handleClientHasError(QAbstractSocket::SocketError error);
|
||||||
|
protected:
|
||||||
|
IosTool *iosTool();
|
||||||
|
RelayServer *server();
|
||||||
|
Ios::ServiceSocket m_serverFileDescriptor;
|
||||||
|
QTcpSocket *m_clientSocket;
|
||||||
|
QSocketNotifier *m_serverNotifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RemotePortRelayer: public Relayer
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
static const int reconnectMsecDelay = 500;
|
||||||
|
static const int maxReconnectAttempts = 2*60*5; // 5 min
|
||||||
|
RemotePortRelayer(GenericRelayServer *parent, QTcpSocket *clientSocket);
|
||||||
|
public slots:
|
||||||
|
void tryRemoteConnect();
|
||||||
|
signals:
|
||||||
|
void didConnect(GenericRelayServer *serv);
|
||||||
|
private:
|
||||||
|
QTimer m_remoteConnectTimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RelayServer: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
RelayServer(IosTool *parent);
|
||||||
|
~RelayServer();
|
||||||
|
bool startServer(int port, bool ipv6);
|
||||||
|
void stopServer();
|
||||||
|
quint16 serverPort();
|
||||||
|
IosTool *iosTool();
|
||||||
|
public slots:
|
||||||
|
void handleNewRelayConnection();
|
||||||
|
protected:
|
||||||
|
virtual void newRelayConnection() = 0;
|
||||||
|
|
||||||
|
QTcpServer m_server;
|
||||||
|
QList<Relayer *> m_connections;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SingleRelayServer: public RelayServer
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SingleRelayServer(IosTool *parent, int serverFileDescriptor);
|
||||||
|
protected:
|
||||||
|
void newRelayConnection() QTC_OVERRIDE;
|
||||||
|
private:
|
||||||
|
int m_serverFileDescriptor;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GenericRelayServer: public RelayServer {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
GenericRelayServer(IosTool *parent, int remotePort,
|
||||||
|
Ios::DeviceSession *deviceSession);
|
||||||
|
protected:
|
||||||
|
void newRelayConnection() QTC_OVERRIDE;
|
||||||
|
private:
|
||||||
|
int m_remotePort;
|
||||||
|
Ios::DeviceSession *m_deviceSession;
|
||||||
|
friend class RemotePortRelayer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GdbRunner: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
GdbRunner(IosTool *iosTool, int gdbFd);
|
||||||
|
public slots:
|
||||||
|
void run();
|
||||||
|
signals:
|
||||||
|
void finished();
|
||||||
|
private:
|
||||||
|
IosTool *m_iosTool;
|
||||||
|
int m_gdbFd;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IosTool: public QObject
|
||||||
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
IosTool(QObject *parent = 0);
|
IosTool(QObject *parent = 0);
|
||||||
@@ -66,24 +174,22 @@ public:
|
|||||||
void writeMsg(const QString &msg);
|
void writeMsg(const QString &msg);
|
||||||
void stopXml(int errorCode);
|
void stopXml(int errorCode);
|
||||||
void writeTextInElement(const QString &output);
|
void writeTextInElement(const QString &output);
|
||||||
|
void stopRelayServers(int errorCode = 0);
|
||||||
|
void writeMaybeBin(const QString &extraMsg, const char *msg, quintptr len);
|
||||||
|
public slots:
|
||||||
|
void errorMsg(const QString &msg);
|
||||||
private slots:
|
private slots:
|
||||||
void isTransferringApp(const QString &bundlePath, const QString &deviceId, int progress,
|
void isTransferringApp(const QString &bundlePath, const QString &deviceId, int progress,
|
||||||
const QString &info);
|
const QString &info);
|
||||||
void didTransferApp(const QString &bundlePath, const QString &deviceId,
|
void didTransferApp(const QString &bundlePath, const QString &deviceId,
|
||||||
Ios::IosDeviceManager::OpStatus status);
|
Ios::IosDeviceManager::OpStatus status);
|
||||||
void didStartApp(const QString &bundlePath, const QString &deviceId,
|
void didStartApp(const QString &bundlePath, const QString &deviceId,
|
||||||
Ios::IosDeviceManager::OpStatus status, int gdbFd);
|
Ios::IosDeviceManager::OpStatus status, int gdbFd,
|
||||||
|
Ios::DeviceSession *deviceSession);
|
||||||
void deviceInfo(const QString &deviceId, const Ios::IosDeviceManager::Dict &info);
|
void deviceInfo(const QString &deviceId, const Ios::IosDeviceManager::Dict &info);
|
||||||
void appOutput(const QString &output);
|
void appOutput(const QString &output);
|
||||||
void errorMsg(const QString &msg);
|
|
||||||
void handleNewConnection();
|
|
||||||
void handleGdbServerSocketHasData(int socket);
|
|
||||||
void handleCreatorHasData();
|
|
||||||
void handleCreatorHasError(QAbstractSocket::SocketError error);
|
|
||||||
private:
|
private:
|
||||||
bool startServer();
|
QMutex m_xmlMutex;
|
||||||
void stopGdbServer(int errorCode = 0);
|
|
||||||
|
|
||||||
int maxProgress;
|
int maxProgress;
|
||||||
int opLeft;
|
int opLeft;
|
||||||
bool debug;
|
bool debug;
|
||||||
@@ -92,15 +198,301 @@ private:
|
|||||||
bool splitAppOutput; // as QXmlStreamReader reports the text attributes atomically it is better to split
|
bool splitAppOutput; // as QXmlStreamReader reports the text attributes atomically it is better to split
|
||||||
Ios::IosDeviceManager::AppOp appOp;
|
Ios::IosDeviceManager::AppOp appOp;
|
||||||
QFile outFile;
|
QFile outFile;
|
||||||
|
QString m_qmlPort;
|
||||||
QXmlStreamWriter out;
|
QXmlStreamWriter out;
|
||||||
int gdbFileDescriptor;
|
SingleRelayServer *gdbServer;
|
||||||
QTcpSocket *creatorSocket;
|
GenericRelayServer *qmlServer;
|
||||||
QSocketNotifier *gdbServerNotifier;
|
friend class GdbRunner;
|
||||||
QTcpServer gdbServer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Relayer::Relayer(RelayServer *parent, QTcpSocket *clientSocket) :
|
||||||
|
QObject(parent), m_serverFileDescriptor(0), m_clientSocket(0), m_serverNotifier(0)
|
||||||
|
{
|
||||||
|
setClientSocket(clientSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
Relayer::~Relayer()
|
||||||
|
{
|
||||||
|
if (m_serverFileDescriptor > 0) {
|
||||||
|
::close(m_serverFileDescriptor);
|
||||||
|
m_serverFileDescriptor = -1;
|
||||||
|
if (m_serverNotifier)
|
||||||
|
delete m_serverNotifier;
|
||||||
|
}
|
||||||
|
if (m_clientSocket->isOpen())
|
||||||
|
m_clientSocket->close();
|
||||||
|
delete m_clientSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Relayer::setClientSocket(QTcpSocket *clientSocket)
|
||||||
|
{
|
||||||
|
QTC_CHECK(!m_clientSocket);
|
||||||
|
m_clientSocket = clientSocket;
|
||||||
|
if (m_clientSocket)
|
||||||
|
connect(m_clientSocket, SIGNAL(error(QAbstractSocket::SocketError)),
|
||||||
|
SLOT(handleClientHasError(QAbstractSocket::SocketError)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Relayer::startRelay(int serverFileDescriptor)
|
||||||
|
{
|
||||||
|
QTC_CHECK(!m_serverFileDescriptor);
|
||||||
|
m_serverFileDescriptor = serverFileDescriptor;
|
||||||
|
if (!m_clientSocket || m_serverFileDescriptor <= 0)
|
||||||
|
return false;
|
||||||
|
fcntl(serverFileDescriptor,F_SETFL, fcntl(serverFileDescriptor, F_GETFL) | O_NONBLOCK);
|
||||||
|
connect(m_clientSocket, SIGNAL(readyRead()), SLOT(handleClientHasData()));
|
||||||
|
m_serverNotifier = new QSocketNotifier(m_serverFileDescriptor, QSocketNotifier::Read, this);
|
||||||
|
connect(m_serverNotifier, SIGNAL(activated(int)), SLOT(handleSocketHasData(int)));
|
||||||
|
// no way to check if an error did happen?
|
||||||
|
if (m_clientSocket->bytesAvailable() > 0)
|
||||||
|
handleClientHasData();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Relayer::handleSocketHasData(int socket)
|
||||||
|
{
|
||||||
|
m_serverNotifier->setEnabled(false);
|
||||||
|
char buf[255];
|
||||||
|
while (true) {
|
||||||
|
qptrdiff rRead = read(socket, &buf, sizeof(buf)-1);
|
||||||
|
if (rRead == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
m_serverNotifier->setEnabled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
iosTool()->errorMsg(qt_error_string(errno));
|
||||||
|
close(socket);
|
||||||
|
iosTool()->stopRelayServers(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rRead == 0) {
|
||||||
|
iosTool()->stopRelayServers(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (echoRelays) {
|
||||||
|
iosTool()->writeMaybeBin(QString::fromLatin1("%1 serverReplies:")
|
||||||
|
.arg((quintptr)(void *)this), buf, rRead);
|
||||||
|
}
|
||||||
|
qint64 pos = 0;
|
||||||
|
while (true) {
|
||||||
|
qint64 writtenNow = m_clientSocket->write(buf + int(pos), rRead);
|
||||||
|
if (writtenNow == -1) {
|
||||||
|
iosTool()->writeMsg(m_clientSocket->errorString());
|
||||||
|
iosTool()->stopRelayServers(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (writtenNow < rRead) {
|
||||||
|
pos += writtenNow;
|
||||||
|
rRead -= qptrdiff(writtenNow);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_clientSocket->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Relayer::handleClientHasData()
|
||||||
|
{
|
||||||
|
char buf[255];
|
||||||
|
while (true) {
|
||||||
|
qint64 toRead = m_clientSocket->bytesAvailable();
|
||||||
|
if (qint64(sizeof(buf)-1) < toRead)
|
||||||
|
toRead = sizeof(buf)-1;
|
||||||
|
qint64 rRead = m_clientSocket->read(buf, toRead);
|
||||||
|
if (rRead == -1) {
|
||||||
|
iosTool()->errorMsg(m_clientSocket->errorString());
|
||||||
|
iosTool()->stopRelayServers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rRead == 0) {
|
||||||
|
if (!m_clientSocket->isOpen())
|
||||||
|
iosTool()->stopRelayServers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int pos = 0;
|
||||||
|
int irep = 0;
|
||||||
|
if (echoRelays) {
|
||||||
|
iosTool()->writeMaybeBin(QString::fromLatin1("%1 clientAsks:")
|
||||||
|
.arg((quintptr)(void *)this), buf, rRead);
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
qptrdiff written = write(m_serverFileDescriptor, buf + pos, rRead);
|
||||||
|
if (written == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
if (++irep > 10) {
|
||||||
|
sleep(1);
|
||||||
|
irep = 0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
iosTool()->errorMsg(qt_error_string(errno));
|
||||||
|
iosTool()->stopRelayServers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (written == 0) {
|
||||||
|
iosTool()->stopRelayServers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (written < rRead) {
|
||||||
|
pos += written;
|
||||||
|
rRead -= written;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Relayer::handleClientHasError(QAbstractSocket::SocketError error)
|
||||||
|
{
|
||||||
|
iosTool()->errorMsg(tr("iOS Debugging connection to creator failed with error %1").arg(error));
|
||||||
|
iosTool()->stopRelayServers();
|
||||||
|
}
|
||||||
|
|
||||||
|
IosTool *Relayer::iosTool()
|
||||||
|
{
|
||||||
|
return (server() ? server()->iosTool() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RelayServer *Relayer::server()
|
||||||
|
{
|
||||||
|
return qobject_cast<RelayServer *>(parent());
|
||||||
|
}
|
||||||
|
|
||||||
|
RemotePortRelayer::RemotePortRelayer(GenericRelayServer *parent, QTcpSocket *clientSocket) :
|
||||||
|
Relayer(parent, clientSocket)
|
||||||
|
{
|
||||||
|
m_remoteConnectTimer.setSingleShot(true);
|
||||||
|
m_remoteConnectTimer.setInterval(reconnectMsecDelay);
|
||||||
|
connect(&m_remoteConnectTimer, SIGNAL(timeout()),
|
||||||
|
SLOT(tryRemoteConnect()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemotePortRelayer::tryRemoteConnect()
|
||||||
|
{
|
||||||
|
iosTool()->errorMsg(QLatin1String("tryRemoteConnect"));
|
||||||
|
if (m_serverFileDescriptor > 0)
|
||||||
|
return;
|
||||||
|
Ios::ServiceSocket ss;
|
||||||
|
GenericRelayServer *grServer = qobject_cast<GenericRelayServer *>(server());
|
||||||
|
if (!grServer)
|
||||||
|
return;
|
||||||
|
if (grServer->m_deviceSession->connectToPort(grServer->m_remotePort, &ss)) {
|
||||||
|
if (ss > 0) {
|
||||||
|
iosTool()->errorMsg(QString::fromLatin1("tryRemoteConnect *succeeded* on remote port %1")
|
||||||
|
.arg(grServer->m_remotePort));
|
||||||
|
startRelay(ss);
|
||||||
|
emit didConnect(grServer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iosTool()->errorMsg(QString::fromLatin1("tryRemoteConnect *failed* on remote port %1")
|
||||||
|
.arg(grServer->m_remotePort));
|
||||||
|
m_remoteConnectTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
RelayServer::RelayServer(IosTool *parent):
|
||||||
|
QObject(parent)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
RelayServer::~RelayServer()
|
||||||
|
{
|
||||||
|
stopServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RelayServer::startServer(int port, bool ipv6)
|
||||||
|
{
|
||||||
|
QTC_CHECK(!m_server.isListening());
|
||||||
|
m_server.setMaxPendingConnections(1);
|
||||||
|
connect(&m_server, SIGNAL(newConnection()), SLOT(handleNewRelayConnection()));
|
||||||
|
quint16 portValue = static_cast<quint16>(port);
|
||||||
|
if (port < 0 || port > 0xFFFF)
|
||||||
|
return false;
|
||||||
|
if (ipv6)
|
||||||
|
return m_server.listen(QHostAddress(QHostAddress::LocalHostIPv6), portValue);
|
||||||
|
else
|
||||||
|
return m_server.listen(QHostAddress(QHostAddress::LocalHost), portValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RelayServer::stopServer()
|
||||||
|
{
|
||||||
|
foreach (Relayer *connection, m_connections)
|
||||||
|
delete connection;
|
||||||
|
if (m_server.isListening())
|
||||||
|
m_server.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint16 RelayServer::serverPort()
|
||||||
|
{
|
||||||
|
return m_server.serverPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
IosTool *RelayServer::iosTool()
|
||||||
|
{
|
||||||
|
return qobject_cast<IosTool *>(parent());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RelayServer::handleNewRelayConnection()
|
||||||
|
{
|
||||||
|
iosTool()->errorMsg(QLatin1String("handleNewRelayConnection"));
|
||||||
|
newRelayConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
SingleRelayServer::SingleRelayServer(IosTool *parent,
|
||||||
|
int serverFileDescriptor) :
|
||||||
|
RelayServer(parent)
|
||||||
|
{
|
||||||
|
m_serverFileDescriptor = serverFileDescriptor;
|
||||||
|
if (m_serverFileDescriptor > 0)
|
||||||
|
fcntl(m_serverFileDescriptor, F_SETFL, fcntl(m_serverFileDescriptor, F_GETFL, 0) | O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleRelayServer::newRelayConnection()
|
||||||
|
{
|
||||||
|
if (m_connections.size() > 0) {
|
||||||
|
m_server.close();
|
||||||
|
QTcpSocket *s = m_server.nextPendingConnection();
|
||||||
|
delete s;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QTcpSocket *clientSocket = m_server.nextPendingConnection();
|
||||||
|
if (clientSocket) {
|
||||||
|
Relayer *newConnection = new Relayer(this, clientSocket);
|
||||||
|
m_connections.append(newConnection);
|
||||||
|
newConnection->startRelay(m_serverFileDescriptor);
|
||||||
|
}
|
||||||
|
m_server.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericRelayServer::GenericRelayServer(IosTool *parent, int remotePort,
|
||||||
|
Ios::DeviceSession *deviceSession) :
|
||||||
|
RelayServer(parent),
|
||||||
|
m_remotePort(remotePort),
|
||||||
|
m_deviceSession(deviceSession)
|
||||||
|
{
|
||||||
|
parent->errorMsg(QLatin1String("created qml server"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GenericRelayServer::newRelayConnection()
|
||||||
|
{
|
||||||
|
QTcpSocket *clientSocket = m_server.nextPendingConnection();
|
||||||
|
if (clientSocket) {
|
||||||
|
iosTool()->errorMsg(QString::fromLatin1("setting up relayer for new connection"));
|
||||||
|
RemotePortRelayer *newConnection = new RemotePortRelayer(this, clientSocket);
|
||||||
|
m_connections.append(newConnection);
|
||||||
|
newConnection->tryRemoteConnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IosTool::IosTool(QObject *parent):
|
IosTool::IosTool(QObject *parent):
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
|
m_xmlMutex(QMutex::Recursive),
|
||||||
maxProgress(0),
|
maxProgress(0),
|
||||||
opLeft(0),
|
opLeft(0),
|
||||||
debug(false),
|
debug(false),
|
||||||
@@ -110,9 +502,8 @@ IosTool::IosTool(QObject *parent):
|
|||||||
appOp(Ios::IosDeviceManager::None),
|
appOp(Ios::IosDeviceManager::None),
|
||||||
outFile(),
|
outFile(),
|
||||||
out(&outFile),
|
out(&outFile),
|
||||||
gdbFileDescriptor(-1),
|
gdbServer(0),
|
||||||
creatorSocket(0),
|
qmlServer(0)
|
||||||
gdbServerNotifier(0)
|
|
||||||
{
|
{
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||||
outFile.open(stdout, QIODevice::WriteOnly, QFile::DontCloseHandle);
|
outFile.open(stdout, QIODevice::WriteOnly, QFile::DontCloseHandle);
|
||||||
@@ -125,8 +516,6 @@ IosTool::IosTool(QObject *parent):
|
|||||||
|
|
||||||
IosTool::~IosTool()
|
IosTool::~IosTool()
|
||||||
{
|
{
|
||||||
delete creatorSocket; // not strictly required
|
|
||||||
delete gdbServerNotifier; // not strictly required
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IosTool::run(const QStringList &args)
|
void IosTool::run(const QStringList &args)
|
||||||
@@ -161,6 +550,8 @@ void IosTool::run(const QStringList &args)
|
|||||||
appOp = Ios::IosDeviceManager::AppOp(appOp | Ios::IosDeviceManager::Run);
|
appOp = Ios::IosDeviceManager::AppOp(appOp | Ios::IosDeviceManager::Run);
|
||||||
} else if (arg == QLatin1String("-ipv6")) {
|
} else if (arg == QLatin1String("-ipv6")) {
|
||||||
ipv6 = true;
|
ipv6 = true;
|
||||||
|
} else if (arg == QLatin1String("-verbose")) {
|
||||||
|
echoRelays = true;
|
||||||
} else if (arg == QLatin1String("-debug")) {
|
} else if (arg == QLatin1String("-debug")) {
|
||||||
appOp = Ios::IosDeviceManager::AppOp(appOp | Ios::IosDeviceManager::Run);
|
appOp = Ios::IosDeviceManager::AppOp(appOp | Ios::IosDeviceManager::Run);
|
||||||
debug = true;
|
debug = true;
|
||||||
@@ -180,8 +571,8 @@ void IosTool::run(const QStringList &args)
|
|||||||
printHelp = true;
|
printHelp = true;
|
||||||
}
|
}
|
||||||
} else if (arg == QLatin1String("-extra-args")) {
|
} else if (arg == QLatin1String("-extra-args")) {
|
||||||
++iarg;
|
|
||||||
extraArgs = args.mid(iarg, args.size() - iarg);
|
extraArgs = args.mid(iarg, args.size() - iarg);
|
||||||
|
iarg = args.size();
|
||||||
} else if (arg == QLatin1String("-help") || arg == QLatin1String("--help")) {
|
} else if (arg == QLatin1String("-help") || arg == QLatin1String("--help")) {
|
||||||
printHelp = true;
|
printHelp = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -191,7 +582,7 @@ void IosTool::run(const QStringList &args)
|
|||||||
if (printHelp) {
|
if (printHelp) {
|
||||||
out.writeStartElement(QLatin1String("msg"));
|
out.writeStartElement(QLatin1String("msg"));
|
||||||
out.writeCharacters(QLatin1String("iosTool [-device-id <deviceId>] [-bundle <pathToBundle>] [-deploy] [-run] [-debug]\n"));
|
out.writeCharacters(QLatin1String("iosTool [-device-id <deviceId>] [-bundle <pathToBundle>] [-deploy] [-run] [-debug]\n"));
|
||||||
out.writeCharacters(QLatin1String(" [-device-info] [-timeout <timeoutIn_ms>]\n")); // to do pass in env as stub does
|
out.writeCharacters(QLatin1String(" [-device-info] [-timeout <timeoutIn_ms>] [-verbose]\n")); // to do pass in env as stub does
|
||||||
out.writeCharacters(QLatin1String(" [-extra-args <arguments for the target app>]"));
|
out.writeCharacters(QLatin1String(" [-extra-args <arguments for the target app>]"));
|
||||||
out.writeEndElement();
|
out.writeEndElement();
|
||||||
doExit(-1);
|
doExit(-1);
|
||||||
@@ -202,13 +593,23 @@ void IosTool::run(const QStringList &args)
|
|||||||
SLOT(isTransferringApp(QString,QString,int,QString)));
|
SLOT(isTransferringApp(QString,QString,int,QString)));
|
||||||
connect(manager,SIGNAL(didTransferApp(QString,QString,Ios::IosDeviceManager::OpStatus)),
|
connect(manager,SIGNAL(didTransferApp(QString,QString,Ios::IosDeviceManager::OpStatus)),
|
||||||
SLOT(didTransferApp(QString,QString,Ios::IosDeviceManager::OpStatus)));
|
SLOT(didTransferApp(QString,QString,Ios::IosDeviceManager::OpStatus)));
|
||||||
connect(manager,SIGNAL(didStartApp(QString,QString,Ios::IosDeviceManager::OpStatus,int)),
|
connect(manager,SIGNAL(didStartApp(QString,QString,Ios::IosDeviceManager::OpStatus,int,Ios::DeviceSession *)),
|
||||||
SLOT(didStartApp(QString,QString,Ios::IosDeviceManager::OpStatus,int)));
|
SLOT(didStartApp(QString,QString,Ios::IosDeviceManager::OpStatus,int,Ios::DeviceSession *)));
|
||||||
connect(manager,SIGNAL(deviceInfo(QString,Ios::IosDeviceManager::Dict)),
|
connect(manager,SIGNAL(deviceInfo(QString,Ios::IosDeviceManager::Dict)),
|
||||||
SLOT(deviceInfo(QString,Ios::IosDeviceManager::Dict)));
|
SLOT(deviceInfo(QString,Ios::IosDeviceManager::Dict)));
|
||||||
connect(manager,SIGNAL(appOutput(QString)), SLOT(appOutput(QString)));
|
connect(manager,SIGNAL(appOutput(QString)), SLOT(appOutput(QString)));
|
||||||
connect(manager,SIGNAL(errorMsg(QString)), SLOT(errorMsg(QString)));
|
connect(manager,SIGNAL(errorMsg(QString)), SLOT(errorMsg(QString)));
|
||||||
manager->watchDevices();
|
manager->watchDevices();
|
||||||
|
QRegExp qmlPortRe=QRegExp(QLatin1String("-qmljsdebugger=port:([0-9]+)"));
|
||||||
|
foreach (const QString &arg, extraArgs) {
|
||||||
|
if (qmlPortRe.indexIn(arg) == 0) {
|
||||||
|
bool ok;
|
||||||
|
int qmlPort = qmlPortRe.cap(1).toInt(&ok);
|
||||||
|
if (ok && qmlPort > 0 && qmlPort <= 0xFFFF)
|
||||||
|
m_qmlPort = qmlPortRe.cap(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (deviceInfo) {
|
if (deviceInfo) {
|
||||||
if (!bundlePath.isEmpty())
|
if (!bundlePath.isEmpty())
|
||||||
writeMsg("-device-info overrides bundlePath");
|
writeMsg("-device-info overrides bundlePath");
|
||||||
@@ -235,6 +636,7 @@ void IosTool::run(const QStringList &args)
|
|||||||
|
|
||||||
void IosTool::stopXml(int errorCode)
|
void IosTool::stopXml(int errorCode)
|
||||||
{
|
{
|
||||||
|
QMutexLocker l(&m_xmlMutex);
|
||||||
out.writeEmptyElement(QLatin1String("exit"));
|
out.writeEmptyElement(QLatin1String("exit"));
|
||||||
out.writeAttribute(QLatin1String("code"), QString::number(errorCode));
|
out.writeAttribute(QLatin1String("code"), QString::number(errorCode));
|
||||||
out.writeEndElement(); // result element (hopefully)
|
out.writeEndElement(); // result element (hopefully)
|
||||||
@@ -254,6 +656,7 @@ void IosTool::isTransferringApp(const QString &bundlePath, const QString &device
|
|||||||
{
|
{
|
||||||
Q_UNUSED(bundlePath);
|
Q_UNUSED(bundlePath);
|
||||||
Q_UNUSED(deviceId);
|
Q_UNUSED(deviceId);
|
||||||
|
QMutexLocker l(&m_xmlMutex);
|
||||||
out.writeStartElement(QLatin1String("status"));
|
out.writeStartElement(QLatin1String("status"));
|
||||||
out.writeAttribute(QLatin1String("progress"), QString::number(progress));
|
out.writeAttribute(QLatin1String("progress"), QString::number(progress));
|
||||||
out.writeAttribute(QLatin1String("max_progress"), QString::number(maxProgress));
|
out.writeAttribute(QLatin1String("max_progress"), QString::number(maxProgress));
|
||||||
@@ -267,6 +670,8 @@ void IosTool::didTransferApp(const QString &bundlePath, const QString &deviceId,
|
|||||||
{
|
{
|
||||||
Q_UNUSED(bundlePath);
|
Q_UNUSED(bundlePath);
|
||||||
Q_UNUSED(deviceId);
|
Q_UNUSED(deviceId);
|
||||||
|
{
|
||||||
|
QMutexLocker l(&m_xmlMutex);
|
||||||
if (status == Ios::IosDeviceManager::Success) {
|
if (status == Ios::IosDeviceManager::Success) {
|
||||||
out.writeStartElement(QLatin1String("status"));
|
out.writeStartElement(QLatin1String("status"));
|
||||||
out.writeAttribute(QLatin1String("progress"), QString::number(maxProgress));
|
out.writeAttribute(QLatin1String("progress"), QString::number(maxProgress));
|
||||||
@@ -281,15 +686,19 @@ void IosTool::didTransferApp(const QString &bundlePath, const QString &deviceId,
|
|||||||
QLatin1String("FAILURE"));
|
QLatin1String("FAILURE"));
|
||||||
//out.writeCharacters(QString()); // trigger a complete closing of the empty element
|
//out.writeCharacters(QString()); // trigger a complete closing of the empty element
|
||||||
outFile.flush();
|
outFile.flush();
|
||||||
|
}
|
||||||
if (status != Ios::IosDeviceManager::Success || --opLeft == 0)
|
if (status != Ios::IosDeviceManager::Success || --opLeft == 0)
|
||||||
doExit((status == Ios::IosDeviceManager::Success) ? 0 : -1);
|
doExit((status == Ios::IosDeviceManager::Success) ? 0 : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId,
|
void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId,
|
||||||
Ios::IosDeviceManager::OpStatus status, int gdbFd)
|
Ios::IosDeviceManager::OpStatus status, int gdbFd,
|
||||||
|
Ios::DeviceSession *deviceSession)
|
||||||
{
|
{
|
||||||
Q_UNUSED(bundlePath);
|
Q_UNUSED(bundlePath);
|
||||||
Q_UNUSED(deviceId);
|
Q_UNUSED(deviceId);
|
||||||
|
{
|
||||||
|
QMutexLocker l(&m_xmlMutex);
|
||||||
out.writeEmptyElement(QLatin1String("app_started"));
|
out.writeEmptyElement(QLatin1String("app_started"));
|
||||||
out.writeAttribute(QLatin1String("status"),
|
out.writeAttribute(QLatin1String("status"),
|
||||||
(status == Ios::IosDeviceManager::Success) ?
|
(status == Ios::IosDeviceManager::Success) ?
|
||||||
@@ -297,6 +706,7 @@ void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId,
|
|||||||
QLatin1String("FAILURE"));
|
QLatin1String("FAILURE"));
|
||||||
//out.writeCharacters(QString()); // trigger a complete closing of the empty element
|
//out.writeCharacters(QString()); // trigger a complete closing of the empty element
|
||||||
outFile.flush();
|
outFile.flush();
|
||||||
|
}
|
||||||
if (status != Ios::IosDeviceManager::Success || appOp == Ios::IosDeviceManager::Install) {
|
if (status != Ios::IosDeviceManager::Success || appOp == Ios::IosDeviceManager::Install) {
|
||||||
doExit();
|
doExit();
|
||||||
return;
|
return;
|
||||||
@@ -311,29 +721,45 @@ void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId,
|
|||||||
doExit(-3);
|
doExit(-3);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (deviceSession) {
|
||||||
|
int qmlPort = deviceSession->qmljsDebugPort();
|
||||||
|
if (qmlPort) {
|
||||||
|
qmlServer = new GenericRelayServer(this, qmlPort, deviceSession);
|
||||||
|
qmlServer->startServer(0, ipv6);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (debug) {
|
if (debug) {
|
||||||
gdbFileDescriptor=gdbFd;
|
gdbServer = new SingleRelayServer(this, gdbFd);
|
||||||
if (!startServer()) {
|
if (!gdbServer->startServer(0, ipv6)) {
|
||||||
doExit(-4);
|
doExit(-4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
out.writeTextElement(QLatin1String("gdb_server_port"),
|
|
||||||
QString::number(gdbServer.serverPort()));
|
|
||||||
outFile.flush();
|
|
||||||
} else {
|
|
||||||
if (!splitAppOutput) {
|
|
||||||
out.writeStartElement(QLatin1String("app_output"));
|
|
||||||
inAppOutput = true;
|
|
||||||
}
|
}
|
||||||
outFile.flush();
|
{
|
||||||
Ios::IosDeviceManager::instance()->processGdbServer(gdbFd);
|
QMutexLocker l(&m_xmlMutex);
|
||||||
if (!splitAppOutput) {
|
out.writeStartElement(QLatin1String("server_ports"));
|
||||||
inAppOutput = false;
|
out.writeAttribute(QLatin1String("gdb_server"),
|
||||||
|
QString::number(gdbServer ? gdbServer->serverPort() : 0));
|
||||||
|
out.writeAttribute(QLatin1String("qml_server"),
|
||||||
|
QString::number(qmlServer ? qmlServer->serverPort() : 0));
|
||||||
out.writeEndElement();
|
out.writeEndElement();
|
||||||
}
|
|
||||||
outFile.flush();
|
outFile.flush();
|
||||||
close(gdbFd);
|
}
|
||||||
doExit();
|
if (!debug) {
|
||||||
|
GdbRunner *gdbRunner = new GdbRunner(this, gdbFd);
|
||||||
|
if (qmlServer) {
|
||||||
|
// we should not stop the event handling of the main thread
|
||||||
|
// all output moves to the new thread (other option would be to signal it back)
|
||||||
|
QThread *gdbProcessThread = new QThread();
|
||||||
|
gdbRunner->moveToThread(gdbProcessThread);
|
||||||
|
QObject::connect(gdbProcessThread, SIGNAL(started()), gdbRunner, SLOT(run()));
|
||||||
|
QObject::connect(gdbRunner, SIGNAL(finished()), gdbProcessThread, SLOT(quit()));
|
||||||
|
QObject::connect(gdbProcessThread, SIGNAL(finished()), gdbProcessThread, SLOT(deleteLater()));
|
||||||
|
gdbProcessThread->start();
|
||||||
|
} else {
|
||||||
|
gdbRunner->setParent(this);
|
||||||
|
gdbRunner->run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,6 +770,7 @@ void IosTool::writeMsg(const char *msg)
|
|||||||
|
|
||||||
void IosTool::writeMsg(const QString &msg)
|
void IosTool::writeMsg(const QString &msg)
|
||||||
{
|
{
|
||||||
|
QMutexLocker l(&m_xmlMutex);
|
||||||
out.writeStartElement(QLatin1String("msg"));
|
out.writeStartElement(QLatin1String("msg"));
|
||||||
writeTextInElement(msg);
|
writeTextInElement(msg);
|
||||||
out.writeCharacters(QLatin1String("\n"));
|
out.writeCharacters(QLatin1String("\n"));
|
||||||
@@ -351,9 +778,41 @@ void IosTool::writeMsg(const QString &msg)
|
|||||||
outFile.flush();
|
outFile.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IosTool::writeMaybeBin(const QString &extraMsg, const char *msg, quintptr len)
|
||||||
|
{
|
||||||
|
char *buf2 = new char[len * 2 + 4];
|
||||||
|
buf2[0] = '[';
|
||||||
|
const char toHex[] = "0123456789abcdef";
|
||||||
|
for (quintptr i = 0; i < len; ++i) {
|
||||||
|
buf2[2 * i + 1] = toHex[(0xF & (msg[i] >> 4))];
|
||||||
|
buf2[2 * i + 2] = toHex[(0xF & msg[i])];
|
||||||
|
}
|
||||||
|
buf2[2 * len + 1] = ']';
|
||||||
|
buf2[2 * len + 2] = ' ';
|
||||||
|
buf2[2 * len + 3] = 0;
|
||||||
|
|
||||||
|
QMutexLocker l(&m_xmlMutex);
|
||||||
|
out.writeStartElement(QLatin1String("msg"));
|
||||||
|
out.writeCharacters(extraMsg);
|
||||||
|
out.writeCharacters(QLatin1String(buf2));
|
||||||
|
for (quintptr i = 0; i < len; ++i) {
|
||||||
|
if (msg[i] < 0x20 || msg[i] > 0x7f)
|
||||||
|
buf2[i] = '_';
|
||||||
|
else
|
||||||
|
buf2[i] = msg[i];
|
||||||
|
}
|
||||||
|
buf2[len] = 0;
|
||||||
|
out.writeCharacters(QLatin1String(buf2));
|
||||||
|
delete[] buf2;
|
||||||
|
out.writeEndElement();
|
||||||
|
outFile.flush();
|
||||||
|
}
|
||||||
|
|
||||||
void IosTool::deviceInfo(const QString &deviceId, const Ios::IosDeviceManager::Dict &devInfo)
|
void IosTool::deviceInfo(const QString &deviceId, const Ios::IosDeviceManager::Dict &devInfo)
|
||||||
{
|
{
|
||||||
Q_UNUSED(deviceId);
|
Q_UNUSED(deviceId);
|
||||||
|
{
|
||||||
|
QMutexLocker l(&m_xmlMutex);
|
||||||
out.writeTextElement(QLatin1String("device_id"), deviceId);
|
out.writeTextElement(QLatin1String("device_id"), deviceId);
|
||||||
out.writeStartElement(QLatin1String("device_info"));
|
out.writeStartElement(QLatin1String("device_info"));
|
||||||
QMapIterator<QString,QString> i(devInfo);
|
QMapIterator<QString,QString> i(devInfo);
|
||||||
@@ -366,6 +825,7 @@ void IosTool::deviceInfo(const QString &deviceId, const Ios::IosDeviceManager::D
|
|||||||
}
|
}
|
||||||
out.writeEndElement();
|
out.writeEndElement();
|
||||||
outFile.flush();
|
outFile.flush();
|
||||||
|
}
|
||||||
doExit();
|
doExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,6 +836,7 @@ void IosTool::writeTextInElement(const QString &output)
|
|||||||
int oldPos = 0;
|
int oldPos = 0;
|
||||||
|
|
||||||
while ((pos = controlCharRe.indexIn(output, pos)) != -1) {
|
while ((pos = controlCharRe.indexIn(output, pos)) != -1) {
|
||||||
|
QMutexLocker l(&m_xmlMutex);
|
||||||
out.writeCharacters(output.mid(oldPos, pos - oldPos));
|
out.writeCharacters(output.mid(oldPos, pos - oldPos));
|
||||||
out.writeEmptyElement(QLatin1String("control_char"));
|
out.writeEmptyElement(QLatin1String("control_char"));
|
||||||
out.writeAttribute(QLatin1String("code"), QString::number(output.at(pos).toLatin1()));
|
out.writeAttribute(QLatin1String("code"), QString::number(output.at(pos).toLatin1()));
|
||||||
@@ -387,6 +848,7 @@ void IosTool::writeTextInElement(const QString &output)
|
|||||||
|
|
||||||
void IosTool::appOutput(const QString &output)
|
void IosTool::appOutput(const QString &output)
|
||||||
{
|
{
|
||||||
|
QMutexLocker l(&m_xmlMutex);
|
||||||
if (!inAppOutput)
|
if (!inAppOutput)
|
||||||
out.writeStartElement(QLatin1String("app_output"));
|
out.writeStartElement(QLatin1String("app_output"));
|
||||||
writeTextInElement(output);
|
writeTextInElement(output);
|
||||||
@@ -400,172 +862,71 @@ void IosTool::errorMsg(const QString &msg)
|
|||||||
writeMsg(msg);
|
writeMsg(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IosTool::handleNewConnection()
|
void IosTool::stopRelayServers(int errorCode)
|
||||||
{
|
{
|
||||||
if (creatorSocket) {
|
if (echoRelays)
|
||||||
gdbServer.close();
|
|
||||||
QTcpSocket *s = gdbServer.nextPendingConnection();
|
|
||||||
delete s;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
creatorSocket = gdbServer.nextPendingConnection();
|
|
||||||
connect(creatorSocket, SIGNAL(readyRead()), SLOT(handleCreatorHasData()));
|
|
||||||
connect(creatorSocket, SIGNAL(error(QAbstractSocket::SocketError)),
|
|
||||||
SLOT(handleCreatorHasError(QAbstractSocket::SocketError)));
|
|
||||||
gdbServerNotifier = new QSocketNotifier(gdbFileDescriptor, QSocketNotifier::Read, this);
|
|
||||||
connect(gdbServerNotifier, SIGNAL(activated(int)), SLOT(handleGdbServerSocketHasData(int)));
|
|
||||||
gdbServer.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IosTool::handleGdbServerSocketHasData(int socket)
|
|
||||||
{
|
|
||||||
gdbServerNotifier->setEnabled(false);
|
|
||||||
char buf[255];
|
|
||||||
while (true) {
|
|
||||||
qptrdiff rRead = read(socket, &buf, sizeof(buf)-1);
|
|
||||||
if (rRead == -1) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
if (errno == EAGAIN) {
|
|
||||||
gdbServerNotifier->setEnabled(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
errorMsg(qt_error_string(errno));
|
|
||||||
close(socket);
|
|
||||||
stopGdbServer(-1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (rRead == 0) {
|
|
||||||
stopGdbServer(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (debugGdbEchoServer) {
|
|
||||||
writeMsg("gdbServerReplies:");
|
|
||||||
buf[rRead] = 0;
|
|
||||||
writeMsg(buf);
|
|
||||||
}
|
|
||||||
qint64 pos = 0;
|
|
||||||
while (true) {
|
|
||||||
qint64 writtenNow = creatorSocket->write(buf + int(pos), rRead);
|
|
||||||
if (writtenNow == -1) {
|
|
||||||
writeMsg(creatorSocket->errorString());
|
|
||||||
stopGdbServer(-1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (writtenNow < rRead) {
|
|
||||||
pos += writtenNow;
|
|
||||||
rRead -= qptrdiff(writtenNow);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IosTool::stopGdbServer(int errorCode)
|
|
||||||
{
|
|
||||||
if (debugGdbEchoServer)
|
|
||||||
writeMsg("gdbServerStops");
|
writeMsg("gdbServerStops");
|
||||||
if (!creatorSocket)
|
if (qmlServer)
|
||||||
return;
|
qmlServer->stopServer();
|
||||||
if (gdbFileDescriptor > 0) {
|
if (gdbServer)
|
||||||
::close(gdbFileDescriptor);
|
gdbServer->stopServer();
|
||||||
gdbFileDescriptor = -1;
|
|
||||||
if (gdbServerNotifier)
|
|
||||||
delete gdbServerNotifier;
|
|
||||||
}
|
|
||||||
if (creatorSocket->isOpen())
|
|
||||||
creatorSocket->close();
|
|
||||||
delete creatorSocket;
|
|
||||||
doExit(errorCode);
|
doExit(errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IosTool::handleCreatorHasData()
|
|
||||||
{
|
|
||||||
char buf[255];
|
|
||||||
while (true) {
|
|
||||||
qint64 toRead = creatorSocket->bytesAvailable();
|
|
||||||
if (qint64(sizeof(buf)-1) < toRead)
|
|
||||||
toRead = sizeof(buf)-1;
|
|
||||||
qint64 rRead = creatorSocket->read(buf, toRead);
|
|
||||||
if (rRead == -1) {
|
|
||||||
errorMsg(creatorSocket->errorString());
|
|
||||||
stopGdbServer();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (rRead == 0) {
|
|
||||||
if (!creatorSocket->isOpen())
|
|
||||||
stopGdbServer();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int pos = 0;
|
|
||||||
int irep = 0;
|
|
||||||
if (debugGdbEchoServer) {
|
|
||||||
writeMsg("sendToGdbServer:");
|
|
||||||
buf[rRead] = 0;
|
|
||||||
writeMsg(buf);
|
|
||||||
}
|
|
||||||
while (true) {
|
|
||||||
qptrdiff written = write(gdbFileDescriptor, buf + pos, rRead);
|
|
||||||
if (written == -1) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
if (errno == EAGAIN) {
|
|
||||||
if (++irep > 10) {
|
|
||||||
sleep(1);
|
|
||||||
irep = 0;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
errorMsg(creatorSocket->errorString());
|
|
||||||
stopGdbServer();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (written == 0) {
|
|
||||||
stopGdbServer();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (written < rRead) {
|
|
||||||
pos += written;
|
|
||||||
rRead -= written;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IosTool::handleCreatorHasError(QAbstractSocket::SocketError error)
|
|
||||||
{
|
|
||||||
errorMsg(tr("iOS Debugging connection to creator failed with error %1").arg(error));
|
|
||||||
stopGdbServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IosTool::startServer()
|
|
||||||
{
|
|
||||||
if (gdbFileDescriptor <= 0 || gdbServer.isListening() || creatorSocket != 0)
|
|
||||||
return false;
|
|
||||||
fcntl(gdbFileDescriptor, F_SETFL, fcntl(gdbFileDescriptor, F_GETFL, 0) | O_NONBLOCK);
|
|
||||||
gdbServer.setMaxPendingConnections(1);
|
|
||||||
connect(&gdbServer, SIGNAL(newConnection()), SLOT(handleNewConnection()));
|
|
||||||
if (ipv6)
|
|
||||||
return gdbServer.listen(QHostAddress(QHostAddress::LocalHostIPv6), 0);
|
|
||||||
else
|
|
||||||
return gdbServer.listen(QHostAddress(QHostAddress::LocalHost), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
// We do not pass the real arguments to QCoreApplication because this wrapper needs to be able
|
||||||
|
// to forward arguments like -qmljsdebugger=... that are filtered by QCoreApplication
|
||||||
|
QStringList args;
|
||||||
|
for (int iarg = 0; iarg < argc ; ++iarg)
|
||||||
|
args << QString::fromLocal8Bit(argv[iarg]);
|
||||||
|
char *qtArg = 0;
|
||||||
|
int qtArgc = 0;
|
||||||
|
if (argc > 0) {
|
||||||
|
qtArg = argv[0];
|
||||||
|
qtArgc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||||
QApplication a(argc, argv);
|
QApplication a(qtArgc, &qtArg);
|
||||||
#else
|
#else
|
||||||
QGuiApplication a(argc, argv);
|
QGuiApplication a(qtArgc, &qtArg);
|
||||||
#endif
|
#endif
|
||||||
IosTool tool;
|
IosTool tool;
|
||||||
tool.run(QCoreApplication::arguments());
|
tool.run(args);
|
||||||
int res = a.exec();
|
int res = a.exec();
|
||||||
exit(res);
|
exit(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "main.moc"
|
#include "main.moc"
|
||||||
|
|
||||||
|
|
||||||
|
GdbRunner::GdbRunner(IosTool *iosTool, int gdbFd) :
|
||||||
|
QObject(0), m_iosTool(iosTool), m_gdbFd(gdbFd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GdbRunner::run()
|
||||||
|
{
|
||||||
|
m_iosTool->errorMsg(QString::fromLatin1("GdbRunner in thread %1").arg((quintptr)(void *)QThread::currentThread()));
|
||||||
|
{
|
||||||
|
QMutexLocker l(&m_iosTool->m_xmlMutex);
|
||||||
|
if (!m_iosTool->splitAppOutput) {
|
||||||
|
m_iosTool->out.writeStartElement(QLatin1String("app_output"));
|
||||||
|
m_iosTool->inAppOutput = true;
|
||||||
|
}
|
||||||
|
m_iosTool->outFile.flush();
|
||||||
|
}
|
||||||
|
Ios::IosDeviceManager::instance()->processGdbServer(m_gdbFd);
|
||||||
|
{
|
||||||
|
QMutexLocker l(&m_iosTool->m_xmlMutex);
|
||||||
|
if (!m_iosTool->splitAppOutput) {
|
||||||
|
m_iosTool->inAppOutput = false;
|
||||||
|
m_iosTool->out.writeEndElement();
|
||||||
|
}
|
||||||
|
m_iosTool->outFile.flush();
|
||||||
|
}
|
||||||
|
close(m_gdbFd);
|
||||||
|
m_iosTool->doExit();
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user