fix: make ipc connection a singleton (#2069)

This commit is contained in:
Yaroslav Gurov
2025-12-16 16:05:31 +01:00
committed by GitHub
parent f50817c43c
commit 8f508783e3
5 changed files with 67 additions and 143 deletions
+54 -89
View File
@@ -1,123 +1,88 @@
#include "ipcclient.h" #include "ipcclient.h"
#include "ipc.h"
#include <QRemoteObjectNode> #include <QRemoteObjectNode>
#include <QtNetwork/qlocalsocket.h>
IpcClient *IpcClient::m_instance = nullptr;
IpcClient::IpcClient(QObject *parent) : QObject(parent) IpcClient::IpcClient(QObject *parent) : QObject(parent)
{ {
} m_localSocket.setServerName(amnezia::getIpcServiceUrl());
IpcClient::~IpcClient() connect(&m_localSocket, &QLocalSocket::connected, this, [this]() {
{ m_ClientNode.addClientSideConnection(&m_localSocket);
if (m_localSocket) m_ipcClient.reset(m_ClientNode.acquire<IpcInterfaceReplica>());
m_localSocket->close(); m_Tun2SocksClient.reset(m_ClientNode.acquire<IpcProcessTun2SocksReplica>());
} m_isSocketConnected = true;
});
bool IpcClient::isSocketConnected() const connect(&m_localSocket, &QLocalSocket::disconnected, [this]() {
{ m_ipcClient.clear();
return m_isSocketConnected; m_Tun2SocksClient.clear();
} m_isSocketConnected = false;
});
void IpcClient::closeAndResetInstance(bool deleteSelf)
{
if (m_localSocket)
{
m_localSocket->disconnectFromServer();
m_localSocket->deleteLater();
m_localSocket.clear();
}
m_ipcClient.reset();
m_Tun2SocksClient.reset();
m_isSocketConnected = false;
if (deleteSelf) {
m_instance = nullptr;
}
} }
IpcClient *IpcClient::Instance() IpcClient *IpcClient::Instance()
{ {
return m_instance; static IpcClient instance;
QMutexLocker locker(&instance.m_mutex);
if (!instance.m_isSocketConnected) {
instance.establishConnection();
}
return &instance;
} }
QSharedPointer<IpcInterfaceReplica> IpcClient::Interface() QSharedPointer<IpcInterfaceReplica> IpcClient::Interface()
{ {
if (!Instance()) auto rep = Instance()->m_ipcClient;
if (!rep) {
qCritical() << "IpcClient::Interface(): Replica is undefined";
return nullptr; return nullptr;
return Instance()->m_ipcClient; }
if (!rep->waitForSource(1000)) {
qCritical() << "IpcClient::Interface(): Failed to initialize replica";
return nullptr;
}
if (!rep->isReplicaValid()) {
qWarning() << "IpcClient::Interface(): Replica is invalid";
}
return rep;
} }
QSharedPointer<IpcProcessTun2SocksReplica> IpcClient::InterfaceTun2Socks() QSharedPointer<IpcProcessTun2SocksReplica> IpcClient::InterfaceTun2Socks()
{ {
if (!Instance()) auto rep = Instance()->m_Tun2SocksClient;
if (!rep) {
qCritical() << "IpcClient::InterfaceTun2Socks: Replica is undefined";
return nullptr; return nullptr;
return Instance()->m_Tun2SocksClient; }
if (!rep->waitForSource(1000)) {
qCritical() << "IpcClient::InterfaceTun2Socks: Failed to initialize replica";
return nullptr;
}
if (!rep->isReplicaValid()) {
qWarning() << "IpcClient::InterfaceTun2Socks(): Replica is invalid";
}
return rep;
} }
bool IpcClient::init(IpcClient *instance) bool IpcClient::establishConnection()
{ {
if (m_instance && m_instance != instance) { m_localSocket.connectToServer();
m_instance->closeAndResetInstance(false); return m_localSocket.waitForConnected();
m_instance->deleteLater();
}
m_instance = instance;
Instance()->m_localSocket = new QLocalSocket(Instance());
connect(Instance()->m_localSocket.data(), &QLocalSocket::connected, &Instance()->m_ClientNode, []() {
Instance()->m_ClientNode.addClientSideConnection(Instance()->m_localSocket.data());
auto cliNode = Instance()->m_ClientNode.acquire<IpcInterfaceReplica>();
cliNode->waitForSource(5000);
Instance()->m_ipcClient.reset(cliNode);
if (!Instance()->m_ipcClient) {
qWarning() << "IpcClient is not ready!";
}
Instance()->m_ipcClient->waitForSource(1000);
if (!Instance()->m_ipcClient->isReplicaValid()) {
qWarning() << "IpcClient replica is not connected!";
}
auto t2sNode = Instance()->m_ClientNode.acquire<IpcProcessTun2SocksReplica>();
t2sNode->waitForSource(5000);
Instance()->m_Tun2SocksClient.reset(t2sNode);
if (!Instance()->m_Tun2SocksClient) {
qWarning() << "IpcClient::m_Tun2SocksClient is not ready!";
}
Instance()->m_Tun2SocksClient->waitForSource(1000);
if (!Instance()->m_Tun2SocksClient->isReplicaValid()) {
qWarning() << "IpcClient::m_Tun2SocksClient replica is not connected!";
}
});
connect(Instance()->m_localSocket, &QLocalSocket::disconnected,
[instance]() { instance->m_isSocketConnected = false; });
Instance()->m_localSocket->connectToServer(amnezia::getIpcServiceUrl());
Instance()->m_localSocket->waitForConnected();
if (!Instance()->m_ipcClient) {
qDebug() << "IpcClient::init failed";
return false;
}
qDebug() << "IpcClient::init succeed";
instance->m_isSocketConnected = (Instance()->m_ipcClient->isReplicaValid() && Instance()->m_Tun2SocksClient->isReplicaValid());
return Instance()->isSocketConnected();
} }
QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess() QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()
{ {
if (!Instance()->m_ipcClient || !Instance()->m_ipcClient->isReplicaValid()) { auto rep = Interface();
qWarning() << "IpcClient::createPrivilegedProcess : IpcClient IpcClient replica is not valid"; if (!rep) {
qCritical() << "IpcClient::createPrivilegedProcess : IpcClient IpcClient replica is not valid";
return nullptr; return nullptr;
} }
QRemoteObjectPendingReply<int> futureResult = Instance()->m_ipcClient->createPrivilegedProcess(); QRemoteObjectPendingReply<int> futureResult = rep->createPrivilegedProcess();
futureResult.waitForFinished(5000); futureResult.waitForFinished(5000);
int pid = futureResult.returnValue(); int pid = futureResult.returnValue();
+3 -9
View File
@@ -17,24 +17,20 @@ public:
explicit IpcClient(QObject *parent = nullptr); explicit IpcClient(QObject *parent = nullptr);
static IpcClient *Instance(); static IpcClient *Instance();
static bool init(IpcClient *instance);
static QSharedPointer<IpcInterfaceReplica> Interface(); static QSharedPointer<IpcInterfaceReplica> Interface();
static QSharedPointer<IpcProcessTun2SocksReplica> InterfaceTun2Socks(); static QSharedPointer<IpcProcessTun2SocksReplica> InterfaceTun2Socks();
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess(); static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
bool isSocketConnected() const; bool isSocketConnected() const;
void closeAndResetInstance(bool deleteSelf = false);
signals: signals:
private: private:
~IpcClient() override; bool establishConnection();
QMutex m_mutex;
QLocalSocket m_localSocket;
QRemoteObjectNode m_ClientNode; QRemoteObjectNode m_ClientNode;
QRemoteObjectNode m_Tun2SocksNode;
QSharedPointer<IpcInterfaceReplica> m_ipcClient; QSharedPointer<IpcInterfaceReplica> m_ipcClient;
QPointer<QLocalSocket> m_localSocket;
QPointer<QLocalSocket> m_tun2socksSocket;
QSharedPointer<IpcProcessTun2SocksReplica> m_Tun2SocksClient; QSharedPointer<IpcProcessTun2SocksReplica> m_Tun2SocksClient;
struct ProcessDescriptor { struct ProcessDescriptor {
@@ -50,8 +46,6 @@ private:
QMap<int, QSharedPointer<ProcessDescriptor>> m_processNodes; QMap<int, QSharedPointer<ProcessDescriptor>> m_processNodes;
bool m_isSocketConnected {false}; bool m_isSocketConnected {false};
static IpcClient *m_instance;
}; };
#endif // IPCCLIENT_H #endif // IPCCLIENT_H
+6 -17
View File
@@ -218,27 +218,16 @@ void VpnConnection::deleteRoutes(const QStringList &ips)
#endif #endif
} }
// TODO: replace with something like
// VpnConnection::withInterface([](iface){ })
bool VpnConnection::InterfaceReady() bool VpnConnection::InterfaceReady()
{ {
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
if (m_IpcClient) { if (auto iface = IpcClient::Interface(); iface == nullptr) {
m_IpcClient->closeAndResetInstance(true); qWarning() << "Error occurred when init IPC client";
m_IpcClient->deleteLater(); emit serviceIsNotReady();
m_IpcClient = nullptr; return false;
} }
if (!m_IpcClient) {
m_IpcClient = new IpcClient(this);
}
if (!m_IpcClient->isSocketConnected()) {
if (!IpcClient::init(m_IpcClient)) {
qWarning() << "Error occurred when init IPC client";
emit serviceIsNotReady();
return false;
}
}
return IpcClient::Interface() != nullptr;
#endif #endif
return true; return true;
} }
-4
View File
@@ -93,10 +93,6 @@ private:
// Only for iOS for now, check counters // Only for iOS for now, check counters
QTimer m_checkTimer; QTimer m_checkTimer;
#ifdef AMNEZIA_DESKTOP
IpcClient *m_IpcClient {nullptr};
#endif
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
AndroidVpnProtocol* androidVpnProtocol = nullptr; AndroidVpnProtocol* androidVpnProtocol = nullptr;
+4 -24
View File
@@ -91,17 +91,8 @@ void Logger::deInit()
bool Logger::setServiceLogsEnabled(bool enabled) bool Logger::setServiceLogsEnabled(bool enabled)
{ {
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
IpcClient *m_IpcClient = new IpcClient; if (auto iface = IpcClient::Interface(); iface) {
iface->setLogsEnabled(enabled);
if (!m_IpcClient->isSocketConnected()) {
if (!IpcClient::init(m_IpcClient)) {
qWarning() << "Error occurred when init IPC client";
return false;
}
}
if (m_IpcClient->Interface()) {
m_IpcClient->Interface()->setLogsEnabled(enabled);
} else { } else {
qWarning() << "Error occurred setting up service logs"; qWarning() << "Error occurred setting up service logs";
return false; return false;
@@ -208,19 +199,8 @@ void Logger::clearLogs(bool isServiceLogger)
void Logger::clearServiceLogs() void Logger::clearServiceLogs()
{ {
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
IpcClient *m_IpcClient = new IpcClient; if (auto iface = IpcClient::Interface(); iface) {
iface->clearLogs();
if (!m_IpcClient->isSocketConnected()) {
if (!IpcClient::init(m_IpcClient)) {
qWarning() << "Error occurred when init IPC client";
return;
}
}
if (m_IpcClient->Interface()) {
m_IpcClient->Interface()->clearLogs();
} else {
qWarning() << "Error occurred cleaning up service logs";
} }
#endif #endif
} }