iOS: Add relay server to route gdb data via service connection

Communication using sockets can no longer be done for gdb server,
though a TCP socket opened using USB MUX still operates normally.
I.e the QML debug server communication remains as is but GDB
server data has to be routed via the secure service connection

Task-number: QTCREATORBUG-24672
Change-Id: I64631d66dc845dd2d7a20c771534ae17e183a9b8
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Vikas Pachdha
2021-03-10 14:25:17 +01:00
parent b152a7287c
commit 35d7bc49f0
4 changed files with 115 additions and 38 deletions

View File

@@ -259,12 +259,12 @@ void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId,
if (deviceSession) { if (deviceSession) {
int qmlPort = deviceSession->qmljsDebugPort(); int qmlPort = deviceSession->qmljsDebugPort();
if (qmlPort) { if (qmlPort) {
qmlServer = new GenericRelayServer(this, qmlPort, deviceSession); qmlServer = new QmlRelayServer(this, qmlPort, deviceSession);
qmlServer->startServer(); qmlServer->startServer();
} }
} }
if (debug) { if (debug) {
gdbServer = new SingleRelayServer(this, gdbFd); gdbServer = new GdbRelayServer(this, gdbFd, conn);
if (!gdbServer->startServer()) { if (!gdbServer->startServer()) {
doExit(-4); doExit(-4);
return; return;

View File

@@ -34,8 +34,8 @@
namespace Ios { namespace Ios {
class GdbRunner; class GdbRunner;
class SingleRelayServer; class GdbRelayServer;
class GenericRelayServer; class QmlRelayServer;
class IosTool: public QObject class IosTool: public QObject
{ {
@@ -79,8 +79,8 @@ private:
QFile outFile; QFile outFile;
QString m_qmlPort; QString m_qmlPort;
QXmlStreamWriter out; QXmlStreamWriter out;
SingleRelayServer *gdbServer; GdbRelayServer *gdbServer;
GenericRelayServer *qmlServer; QmlRelayServer *qmlServer;
GdbRunner *gdbRunner; GdbRunner *gdbRunner;
bool m_echoRelays = false; bool m_echoRelays = false;
friend class GdbRunner; friend class GdbRunner;

View File

@@ -26,6 +26,7 @@
#include "relayserver.h" #include "relayserver.h"
#include "iostool.h" #include "iostool.h"
#include "mobiledevicelib.h"
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
#include <unistd.h> #include <unistd.h>
@@ -45,15 +46,7 @@ Relayer::Relayer(RelayServer *parent, QTcpSocket *clientSocket) :
Relayer::~Relayer() Relayer::~Relayer()
{ {
if (m_serverFileDescriptor > 0) { closeConnection();
::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) void Relayer::setClientSocket(QTcpSocket *clientSocket)
@@ -93,7 +86,7 @@ void Relayer::handleSocketHasData(int socket)
m_serverNotifier->setEnabled(false); m_serverNotifier->setEnabled(false);
char buf[255]; char buf[255];
while (true) { while (true) {
qptrdiff rRead = read(socket, &buf, sizeof(buf)-1); qptrdiff rRead = readData(socket, &buf, sizeof(buf)-1);
if (rRead == -1) { if (rRead == -1) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
@@ -158,7 +151,7 @@ void Relayer::handleClientHasData()
.arg((quintptr)(void *)this), buf, rRead); .arg((quintptr)(void *)this), buf, rRead);
} }
while (true) { while (true) {
qptrdiff written = write(m_serverFileDescriptor, buf + pos, rRead); qptrdiff written = writeData(m_serverFileDescriptor, buf + pos, rRead);
if (written == -1) { if (written == -1) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
@@ -193,6 +186,32 @@ void Relayer::handleClientHasError(QAbstractSocket::SocketError error)
server()->removeRelayConnection(this); server()->removeRelayConnection(this);
} }
int Relayer::readData(int socketFd, void *buf, size_t size)
{
return read(socketFd, buf, size);
}
int Relayer::writeData(int socketFd, const void *data, size_t size)
{
return write(socketFd, data, size);
}
void Relayer::closeConnection()
{
if (m_serverFileDescriptor > 0) {
::close(m_serverFileDescriptor);
m_serverFileDescriptor = -1;
if (m_serverNotifier) {
delete m_serverNotifier;
m_serverNotifier = nullptr;
}
}
if (m_clientSocket->isOpen())
m_clientSocket->close();
delete m_clientSocket;
m_clientSocket = nullptr;
}
IosTool *Relayer::iosTool() const IosTool *Relayer::iosTool() const
{ {
return (server() ? server()->iosTool() : 0); return (server() ? server()->iosTool() : 0);
@@ -203,7 +222,7 @@ RelayServer *Relayer::server() const
return qobject_cast<RelayServer *>(parent()); return qobject_cast<RelayServer *>(parent());
} }
RemotePortRelayer::RemotePortRelayer(GenericRelayServer *parent, QTcpSocket *clientSocket) : RemotePortRelayer::RemotePortRelayer(QmlRelayServer *parent, QTcpSocket *clientSocket) :
Relayer(parent, clientSocket) Relayer(parent, clientSocket)
{ {
m_remoteConnectTimer.setSingleShot(true); m_remoteConnectTimer.setSingleShot(true);
@@ -217,7 +236,7 @@ void RemotePortRelayer::tryRemoteConnect()
if (m_serverFileDescriptor > 0) if (m_serverFileDescriptor > 0)
return; return;
ServiceSocket ss; ServiceSocket ss;
GenericRelayServer *grServer = qobject_cast<GenericRelayServer *>(server()); QmlRelayServer *grServer = qobject_cast<QmlRelayServer *>(server());
if (!grServer) if (!grServer)
return; return;
if (grServer->m_deviceSession->connectToPort(grServer->m_remotePort, &ss)) { if (grServer->m_deviceSession->connectToPort(grServer->m_remotePort, &ss)) {
@@ -294,16 +313,17 @@ void RelayServer::removeRelayConnection(Relayer *relayer)
relayer->deleteLater(); relayer->deleteLater();
} }
SingleRelayServer::SingleRelayServer(IosTool *parent, GdbRelayServer::GdbRelayServer(IosTool *parent,
int serverFileDescriptor) : int serverFileDescriptor, ServiceConnRef conn) :
RelayServer(parent) RelayServer(parent),
m_serverFileDescriptor(serverFileDescriptor),
m_serviceConn(conn)
{ {
m_serverFileDescriptor = serverFileDescriptor;
if (m_serverFileDescriptor > 0) if (m_serverFileDescriptor > 0)
fcntl(m_serverFileDescriptor, F_SETFL, fcntl(m_serverFileDescriptor, F_GETFL, 0) | O_NONBLOCK); fcntl(m_serverFileDescriptor, F_SETFL, fcntl(m_serverFileDescriptor, F_GETFL, 0) | O_NONBLOCK);
} }
void SingleRelayServer::newRelayConnection() void GdbRelayServer::newRelayConnection()
{ {
QTcpSocket *clientSocket = m_ipv4Server.hasPendingConnections() QTcpSocket *clientSocket = m_ipv4Server.hasPendingConnections()
? m_ipv4Server.nextPendingConnection() : m_ipv6Server.nextPendingConnection(); ? m_ipv4Server.nextPendingConnection() : m_ipv6Server.nextPendingConnection();
@@ -312,13 +332,13 @@ void SingleRelayServer::newRelayConnection()
return; return;
} }
if (clientSocket) { if (clientSocket) {
Relayer *newConnection = new Relayer(this, clientSocket); Relayer *newConnection = new ServiceConnectionRelayer(this, clientSocket, m_serviceConn);
m_connections.append(newConnection); m_connections.append(newConnection);
newConnection->startRelay(m_serverFileDescriptor); newConnection->startRelay(m_serverFileDescriptor);
} }
} }
GenericRelayServer::GenericRelayServer(IosTool *parent, int remotePort, QmlRelayServer::QmlRelayServer(IosTool *parent, int remotePort,
Ios::DeviceSession *deviceSession) : Ios::DeviceSession *deviceSession) :
RelayServer(parent), RelayServer(parent),
m_remotePort(remotePort), m_remotePort(remotePort),
@@ -328,7 +348,7 @@ GenericRelayServer::GenericRelayServer(IosTool *parent, int remotePort,
} }
void GenericRelayServer::newRelayConnection() void QmlRelayServer::newRelayConnection()
{ {
QTcpSocket *clientSocket = m_ipv4Server.hasPendingConnections() QTcpSocket *clientSocket = m_ipv4Server.hasPendingConnections()
? m_ipv4Server.nextPendingConnection() : m_ipv6Server.nextPendingConnection(); ? m_ipv4Server.nextPendingConnection() : m_ipv6Server.nextPendingConnection();
@@ -339,4 +359,42 @@ void GenericRelayServer::newRelayConnection()
newConnection->tryRemoteConnect(); newConnection->tryRemoteConnect();
} }
} }
ServiceConnectionRelayer::ServiceConnectionRelayer(RelayServer *parent, QTcpSocket *clientSocket,
ServiceConnRef conn)
: Relayer(parent, clientSocket),
m_serviceConn(conn)
{
}
int ServiceConnectionRelayer::readData(int socketFd, void *buf, size_t size)
{
Q_UNUSED(socketFd)
if (!buf || !m_serviceConn)
return 0;
MobileDeviceLib &mlib = MobileDeviceLib::instance();
return mlib.serviceConnectionReceive(m_serviceConn, buf, size);
}
int ServiceConnectionRelayer::writeData(int socketFd, const void *data, size_t size)
{
Q_UNUSED(socketFd)
if (!data || !m_serviceConn)
return 0;
MobileDeviceLib &mLib = MobileDeviceLib::instance();
return mLib.serviceConnectionSend(m_serviceConn, data, size);
}
void ServiceConnectionRelayer::closeConnection()
{
Relayer::closeConnection();
if (m_serviceConn) {
MobileDeviceLib &mLib = MobileDeviceLib::instance();
mLib.serviceConnectionInvalidate(m_serviceConn);
m_serviceConn = nullptr;
}
}
} }

View File

@@ -38,7 +38,7 @@ namespace Ios {
class DeviceSession; class DeviceSession;
class IosTool; class IosTool;
class RelayServer; class RelayServer;
class GenericRelayServer; class QmlRelayServer;
class Relayer: public QObject class Relayer: public QObject
{ {
@@ -55,11 +55,29 @@ public:
void handleClientHasError(QAbstractSocket::SocketError error); void handleClientHasError(QAbstractSocket::SocketError error);
protected: protected:
virtual int readData(int socketFd, void* buf, size_t size);
virtual int writeData(int socketFd, const void *data, size_t size);
virtual void closeConnection();
IosTool *iosTool() const; IosTool *iosTool() const;
RelayServer *server() const; RelayServer *server() const;
ServiceSocket m_serverFileDescriptor; ServiceSocket m_serverFileDescriptor;
QTcpSocket *m_clientSocket; QTcpSocket *m_clientSocket = nullptr;
QSocketNotifier *m_serverNotifier; QSocketNotifier *m_serverNotifier = nullptr;
};
class ServiceConnectionRelayer : public Relayer
{
public:
ServiceConnectionRelayer(RelayServer *parent, QTcpSocket *clientSocket, ServiceConnRef conn);
protected:
int readData(int socketFd, void* buf, size_t size) override;
int writeData(int socketFd, const void *data, size_t size) override;
void closeConnection() override;
private:
ServiceConnRef m_serviceConn;
}; };
class RemotePortRelayer: public Relayer class RemotePortRelayer: public Relayer
@@ -69,11 +87,11 @@ class RemotePortRelayer: public Relayer
public: public:
static const int reconnectMsecDelay = 500; static const int reconnectMsecDelay = 500;
static const int maxReconnectAttempts = 2*60*5; // 5 min static const int maxReconnectAttempts = 2*60*5; // 5 min
RemotePortRelayer(GenericRelayServer *parent, QTcpSocket *clientSocket); RemotePortRelayer(QmlRelayServer *parent, QTcpSocket *clientSocket);
void tryRemoteConnect(); void tryRemoteConnect();
signals: signals:
void didConnect(GenericRelayServer *serv); void didConnect(QmlRelayServer *serv);
private: private:
QTimer m_remoteConnectTimer; QTimer m_remoteConnectTimer;
@@ -103,27 +121,28 @@ protected:
QList<Relayer *> m_connections; QList<Relayer *> m_connections;
}; };
class SingleRelayServer: public RelayServer class GdbRelayServer: public RelayServer
{ {
Q_OBJECT Q_OBJECT
public: public:
SingleRelayServer(IosTool *parent, int serverFileDescriptor); GdbRelayServer(IosTool *parent, int serverFileDescriptor, ServiceConnRef conn);
protected: protected:
void newRelayConnection() override; void newRelayConnection() override;
private: private:
int m_serverFileDescriptor; int m_serverFileDescriptor = -1;
ServiceConnRef m_serviceConn = nullptr;
}; };
class GenericRelayServer: public RelayServer class QmlRelayServer: public RelayServer
{ {
Q_OBJECT Q_OBJECT
public: public:
GenericRelayServer(IosTool *parent, int remotePort, QmlRelayServer(IosTool *parent, int remotePort,
Ios::DeviceSession *deviceSession); Ios::DeviceSession *deviceSession);
protected: protected:
void newRelayConnection() override; void newRelayConnection() override;