fix: make ipc client thread-safe (#2075)

This commit is contained in:
Yaroslav Gurov
2025-12-18 13:18:11 +01:00
committed by GitHub
parent 6a3d43fbb0
commit d77eaba500
3 changed files with 104 additions and 28 deletions
+29 -22
View File
@@ -3,6 +3,11 @@
#include <QRemoteObjectNode> #include <QRemoteObjectNode>
#include <QtNetwork/qlocalsocket.h> #include <QtNetwork/qlocalsocket.h>
namespace
{
thread_local IpcClient ipcClient;
}
IpcClient::IpcClient(QObject *parent) : QObject(parent) IpcClient::IpcClient(QObject *parent) : QObject(parent)
{ {
m_localSocket.setServerName(amnezia::getIpcServiceUrl()); m_localSocket.setServerName(amnezia::getIpcServiceUrl());
@@ -14,7 +19,7 @@ IpcClient::IpcClient(QObject *parent) : QObject(parent)
m_isSocketConnected = true; m_isSocketConnected = true;
}); });
connect(&m_localSocket, &QLocalSocket::disconnected, [this]() { connect(&m_localSocket, &QLocalSocket::disconnected, this, [this]() {
m_ipcClient.clear(); m_ipcClient.clear();
m_Tun2SocksClient.clear(); m_Tun2SocksClient.clear();
m_isSocketConnected = false; m_isSocketConnected = false;
@@ -23,22 +28,18 @@ IpcClient::IpcClient(QObject *parent) : QObject(parent)
IpcClient *IpcClient::Instance() IpcClient *IpcClient::Instance()
{ {
static IpcClient instance; if (!ipcClient.m_isSocketConnected) {
ipcClient.establishConnection();
QMutexLocker locker(&instance.m_mutex);
if (!instance.m_isSocketConnected) {
instance.establishConnection();
} }
return &instance; return &ipcClient;
} }
QSharedPointer<IpcInterfaceReplica> IpcClient::Interface() QSharedPointer<IpcInterfaceReplica> IpcClient::Interface()
{ {
auto rep = Instance()->m_ipcClient; QSharedPointer<IpcInterfaceReplica> rep = Instance()->m_ipcClient;
if (!rep) { if (rep.isNull()) {
qCritical() << "IpcClient::Interface(): Replica is undefined"; qCritical() << "IpcClient::Interface(): Failed to acquire replica";
return nullptr; return nullptr;
} }
if (!rep->waitForSource(1000)) { if (!rep->waitForSource(1000)) {
@@ -53,8 +54,8 @@ QSharedPointer<IpcInterfaceReplica> IpcClient::Interface()
QSharedPointer<IpcProcessTun2SocksReplica> IpcClient::InterfaceTun2Socks() QSharedPointer<IpcProcessTun2SocksReplica> IpcClient::InterfaceTun2Socks()
{ {
auto rep = Instance()->m_Tun2SocksClient; QSharedPointer<IpcProcessTun2SocksReplica> rep = Instance()->m_Tun2SocksClient;
if (!rep) { if (rep.isNull()) {
qCritical() << "IpcClient::InterfaceTun2Socks: Replica is undefined"; qCritical() << "IpcClient::InterfaceTun2Socks: Replica is undefined";
return nullptr; return nullptr;
} }
@@ -76,19 +77,20 @@ bool IpcClient::establishConnection()
QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess() QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()
{ {
auto rep = Interface(); QSharedPointer<IpcInterfaceReplica> rep = Interface();
if (!rep) { if (!rep) {
qCritical() << "IpcClient::createPrivilegedProcess : IpcClient IpcClient replica is not valid"; qCritical() << "IpcClient::createPrivilegedProcess: Replica is invalid";
return nullptr; return nullptr;
} }
QRemoteObjectPendingReply<int> futureResult = rep->createPrivilegedProcess(); QRemoteObjectPendingReply<int> pidReply = rep->createPrivilegedProcess();
futureResult.waitForFinished(5000); if (!pidReply.waitForFinished(5000)){
qCritical() << "IpcClient::createPrivilegedProcess: Failed to execute RO createPrivilegedProcess call";
return nullptr;
}
int pid = futureResult.returnValue(); int pid = pidReply.returnValue();
QSharedPointer<ProcessDescriptor> pd(new ProcessDescriptor());
auto pd = QSharedPointer<ProcessDescriptor>(new ProcessDescriptor());
Instance()->m_processNodes.insert(pid, pd);
pd->localSocket.reset(new QLocalSocket(pd->replicaNode.data())); pd->localSocket.reset(new QLocalSocket(pd->replicaNode.data()));
@@ -96,6 +98,7 @@ QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()
pd->replicaNode->addClientSideConnection(pd->localSocket.data()); pd->replicaNode->addClientSideConnection(pd->localSocket.data());
IpcProcessInterfaceReplica *repl = pd->replicaNode->acquire<IpcProcessInterfaceReplica>(); IpcProcessInterfaceReplica *repl = pd->replicaNode->acquire<IpcProcessInterfaceReplica>();
// TODO: rework the unsafe cast below
PrivilegedProcess *priv = static_cast<PrivilegedProcess *>(repl); PrivilegedProcess *priv = static_cast<PrivilegedProcess *>(repl);
pd->ipcProcess.reset(priv); pd->ipcProcess.reset(priv);
if (!pd->ipcProcess) { if (!pd->ipcProcess) {
@@ -110,8 +113,12 @@ QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()
[pd]() { pd->replicaNode->deleteLater(); }); [pd]() { pd->replicaNode->deleteLater(); });
} }
}); });
pd->localSocket->connectToServer(amnezia::getIpcProcessUrl(pid)); pd->localSocket->connectToServer(amnezia::getIpcProcessUrl(pid));
pd->localSocket->waitForConnected(); if (!pd->localSocket->waitForConnected()) {
qCritical() << "IpcClient::createPrivilegedProcess: Failed to connect to process' socket";
return nullptr;
}
auto processReplica = QSharedPointer<PrivilegedProcess>(pd->ipcProcess); auto processReplica = QSharedPointer<PrivilegedProcess>(pd->ipcProcess);
return processReplica; return processReplica;
-2
View File
@@ -27,7 +27,6 @@ signals:
private: private:
bool establishConnection(); bool establishConnection();
QMutex m_mutex;
QLocalSocket m_localSocket; QLocalSocket m_localSocket;
QRemoteObjectNode m_ClientNode; QRemoteObjectNode m_ClientNode;
QSharedPointer<IpcInterfaceReplica> m_ipcClient; QSharedPointer<IpcInterfaceReplica> m_ipcClient;
@@ -44,7 +43,6 @@ private:
QSharedPointer<QLocalSocket> localSocket; QSharedPointer<QLocalSocket> localSocket;
}; };
QMap<int, QSharedPointer<ProcessDescriptor>> m_processNodes;
bool m_isSocketConnected {false}; bool m_isSocketConnected {false};
}; };
+75 -4
View File
@@ -147,35 +147,64 @@ void IpcServer::cleanUp()
void IpcServer::clearLogs() void IpcServer::clearLogs()
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::clearLogs";
#endif
Logger::clearLogs(true); Logger::clearLogs(true);
} }
bool IpcServer::createTun(const QString &dev, const QString &subnet) bool IpcServer::createTun(const QString &dev, const QString &subnet)
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::createTun";
#endif
return Router::createTun(dev, subnet); return Router::createTun(dev, subnet);
} }
bool IpcServer::deleteTun(const QString &dev) bool IpcServer::deleteTun(const QString &dev)
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::deleteTun";
#endif
return Router::deleteTun(dev); return Router::deleteTun(dev);
} }
bool IpcServer::updateResolvers(const QString &ifname, const QList<QHostAddress> &resolvers) bool IpcServer::updateResolvers(const QString &ifname, const QList<QHostAddress> &resolvers)
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::updateResolvers";
#endif
return Router::updateResolvers(ifname, resolvers); return Router::updateResolvers(ifname, resolvers);
} }
bool IpcServer::restoreResolvers() { bool IpcServer::restoreResolvers()
{
#ifdef MZ_DEBUG
qDebug() << "IpcServer::restoreResolvers";
#endif
return Router::restoreResolvers(); return Router::restoreResolvers();
} }
bool IpcServer::StartRoutingIpv6() bool IpcServer::StartRoutingIpv6()
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::StartRoutingIpv6";
#endif
return Router::StartRoutingIpv6(); return Router::StartRoutingIpv6();
} }
bool IpcServer::StopRoutingIpv6() bool IpcServer::StopRoutingIpv6()
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::StopRoutingIpv6";
#endif
return Router::StopRoutingIpv6(); return Router::StopRoutingIpv6();
} }
@@ -194,59 +223,101 @@ void IpcServer::setLogsEnabled(bool enabled)
bool IpcServer::startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address) bool IpcServer::startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address)
{ {
qDebug() << "startNetworkCheck"; #ifdef MZ_DEBUG
qDebug() << "IpcServer::startNetworkCheck";
#endif
m_pingHelper.start(serverIpv4Gateway, deviceIpv4Address); m_pingHelper.start(serverIpv4Gateway, deviceIpv4Address);
return true; return true;
} }
bool IpcServer::stopNetworkCheck() bool IpcServer::stopNetworkCheck()
{ {
qDebug() << "stopNetworkCheck"; #ifdef MZ_DEBUG
qDebug() << "IpcServer::stopNetworkCheck";
#endif
m_pingHelper.stop(); m_pingHelper.stop();
return true; return true;
} }
bool IpcServer::resetKillSwitchAllowedRange(QStringList ranges) bool IpcServer::resetKillSwitchAllowedRange(QStringList ranges)
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::resetKillSwitchAllowedRange";
#endif
return KillSwitch::instance()->resetAllowedRange(ranges); return KillSwitch::instance()->resetAllowedRange(ranges);
} }
bool IpcServer::addKillSwitchAllowedRange(QStringList ranges) bool IpcServer::addKillSwitchAllowedRange(QStringList ranges)
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::addKillSwitchAllowedRange";
#endif
return KillSwitch::instance()->addAllowedRange(ranges); return KillSwitch::instance()->addAllowedRange(ranges);
} }
bool IpcServer::disableAllTraffic() bool IpcServer::disableAllTraffic()
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::disableAllTraffic";
#endif
return KillSwitch::instance()->disableAllTraffic(); return KillSwitch::instance()->disableAllTraffic();
} }
bool IpcServer::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIndex) bool IpcServer::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIndex)
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::enableKillSwitch";
#endif
return KillSwitch::instance()->enableKillSwitch(configStr, vpnAdapterIndex); return KillSwitch::instance()->enableKillSwitch(configStr, vpnAdapterIndex);
} }
bool IpcServer::disableKillSwitch() bool IpcServer::disableKillSwitch()
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::disableKillSwitch";
#endif
return KillSwitch::instance()->disableKillSwitch(); return KillSwitch::instance()->disableKillSwitch();
} }
bool IpcServer::enablePeerTraffic(const QJsonObject &configStr) bool IpcServer::enablePeerTraffic(const QJsonObject &configStr)
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::enablePeerTraffic";
#endif
return KillSwitch::instance()->enablePeerTraffic(configStr); return KillSwitch::instance()->enablePeerTraffic(configStr);
} }
bool IpcServer::refreshKillSwitch(bool enabled) bool IpcServer::refreshKillSwitch(bool enabled)
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::refreshKillSwitch";
#endif
return KillSwitch::instance()->refresh(enabled); return KillSwitch::instance()->refresh(enabled);
} }
void IpcServer::xrayStart(const QString& cfg) void IpcServer::xrayStart(const QString& cfg)
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::xrayStart";
#endif
return Xray::getInstance().startXray(cfg); return Xray::getInstance().startXray(cfg);
} }
void IpcServer::xrayStop() void IpcServer::xrayStop()
{ {
#ifdef MZ_DEBUG
qDebug() << "IpcServer::xrayStop";
#endif
return Xray::getInstance().stopXray(); return Xray::getInstance().stopXray();
} }