diff --git a/client/core/ipcclient.cpp b/client/core/ipcclient.cpp index 03a3152c..475810a8 100644 --- a/client/core/ipcclient.cpp +++ b/client/core/ipcclient.cpp @@ -1,38 +1,83 @@ #include "ipcclient.h" #include -IpcClient &IpcClient::Instance() +IpcClient *IpcClient::m_instance = nullptr; + +IpcClient::IpcClient(QObject *parent) : QObject(parent) { - static IpcClient s; - return s; + } -bool IpcClient::init() +IpcClient::~IpcClient() { - Instance().m_localSocket->waitForConnected(); + if (m_localSocket) m_localSocket->close(); +} - if (!Instance().m_ipcClient) { +bool IpcClient::isSocketConnected() const +{ + return m_isSocketConnected; +} + +IpcClient *IpcClient::Instance() +{ + return m_instance; +} + +QSharedPointer IpcClient::Interface() +{ + if (!Instance()) return nullptr; + return Instance()->m_ipcClient; +} + +bool IpcClient::init(IpcClient *instance) +{ + 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()); + + Instance()->m_ipcClient.reset(Instance()->m_ClientNode.acquire()); + Instance()->m_ipcClient->waitForSource(1000); + + if (!Instance()->m_ipcClient->isReplicaValid()) { + qWarning() << "IpcClient 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; } - return Instance().m_ipcClient->isReplicaValid(); + qDebug() << "IpcClient::init succeed"; + + return Instance()->m_ipcClient->isReplicaValid(); } QSharedPointer IpcClient::CreatePrivilegedProcess() { #ifndef Q_OS_IOS - if (! Instance().m_ipcClient || ! Instance().m_ipcClient->isReplicaValid()) { + if (! Instance()->m_ipcClient || ! Instance()->m_ipcClient->isReplicaValid()) { qWarning() << "IpcClient::createPrivilegedProcess : IpcClient IpcClient replica is not valid"; return nullptr; } - QRemoteObjectPendingReply futureResult = Instance().m_ipcClient->createPrivilegedProcess(); + QRemoteObjectPendingReply futureResult = Instance()->m_ipcClient->createPrivilegedProcess(); futureResult.waitForFinished(1000); int pid = futureResult.returnValue(); auto pd = QSharedPointer(new ProcessDescriptor()); - Instance().m_processNodes.insert(pid, pd); + Instance()->m_processNodes.insert(pid, pd); pd->localSocket.reset(new QLocalSocket(pd->replicaNode.data())); @@ -65,19 +110,4 @@ QSharedPointer IpcClient::CreatePrivilegedProcess() #endif } -IpcClient::IpcClient(QObject *parent) : QObject(parent) -{ - m_localSocket.reset(new QLocalSocket(this)); - connect(m_localSocket.data(), &QLocalSocket::connected, &m_ClientNode, [this]() { - m_ClientNode.addClientSideConnection(m_localSocket.data()); - m_ipcClient.reset(m_ClientNode.acquire()); - m_ipcClient->waitForSource(1000); - - if (!m_ipcClient->isReplicaValid()) { - qWarning() << "IpcClient replica is not connected!"; - } - - }); - m_localSocket->connectToServer(amnezia::getIpcServiceUrl()); -} diff --git a/client/core/ipcclient.h b/client/core/ipcclient.h index 6eef02b1..1548a6cb 100644 --- a/client/core/ipcclient.h +++ b/client/core/ipcclient.h @@ -19,19 +19,23 @@ class IpcClient : public QObject { Q_OBJECT public: - static IpcClient &Instance(); - static bool init(); - static QSharedPointer Interface() { return Instance().m_ipcClient; } + explicit IpcClient(QObject *parent = nullptr); + + static IpcClient *Instance(); + static bool init(IpcClient *instance); + static QSharedPointer Interface(); static QSharedPointer CreatePrivilegedProcess(); + bool isSocketConnected() const; + signals: private: - explicit IpcClient(QObject *parent = nullptr); + ~IpcClient() override; QRemoteObjectNode m_ClientNode; QSharedPointer m_ipcClient; - QSharedPointer m_localSocket; + QPointer m_localSocket; struct ProcessDescriptor { ProcessDescriptor () { @@ -45,6 +49,9 @@ private: }; QMap> m_processNodes; + bool m_isSocketConnected {false}; + + static IpcClient *m_instance; }; #endif // IPCCLIENT_H diff --git a/client/main.cpp b/client/main.cpp index c3b40b4e..0dad4aa2 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -117,6 +117,8 @@ int main(int argc, char *argv[]) app.setQuitOnLastWindowClosed(false); qRegisterMetaType("VpnProtocol::ConnectionState"); + qRegisterMetaType("ServerCredentials"); + qRegisterMetaType("DockerContainer"); qRegisterMetaType("TransportProto"); qRegisterMetaType("Protocol"); @@ -128,7 +130,7 @@ int main(int argc, char *argv[]) UiLogic *uiLogic = new UiLogic; - QQmlApplicationEngine engine; + QQmlApplicationEngine *engine = new QQmlApplicationEngine; declareQmlPageEnum(); declareQmlProtocolEnum(); @@ -141,29 +143,37 @@ int main(int argc, char *argv[]) qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", protocolProps.get()); const QUrl url(QStringLiteral("qrc:/ui/qml/main.qml")); - QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, + QObject::connect(engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); - engine.rootContext()->setContextProperty("UiLogic", uiLogic); + engine->rootContext()->setContextProperty("UiLogic", uiLogic); - engine.rootContext()->setContextProperty("AppSettingsLogic", uiLogic->appSettingsLogic()); - engine.rootContext()->setContextProperty("GeneralSettingsLogic", uiLogic->generalSettingsLogic()); - engine.rootContext()->setContextProperty("NetworkSettingsLogic", uiLogic->networkSettingsLogic()); - engine.rootContext()->setContextProperty("ServerConfiguringProgressLogic", uiLogic->serverConfiguringProgressLogic()); - engine.rootContext()->setContextProperty("NewServerProtocolsLogic", uiLogic->newServerProtocolsLogic()); - engine.rootContext()->setContextProperty("ServerListLogic", uiLogic->serverListLogic()); - engine.rootContext()->setContextProperty("ServerSettingsLogic", uiLogic->serverSettingsLogic()); - engine.rootContext()->setContextProperty("ServerContainersLogic", uiLogic->serverVpnProtocolsLogic()); - engine.rootContext()->setContextProperty("ShareConnectionLogic", uiLogic->shareConnectionLogic()); - engine.rootContext()->setContextProperty("SitesLogic", uiLogic->sitesLogic()); - engine.rootContext()->setContextProperty("StartPageLogic", uiLogic->startPageLogic()); - engine.rootContext()->setContextProperty("VpnLogic", uiLogic->vpnLogic()); - engine.rootContext()->setContextProperty("WizardLogic", uiLogic->wizardLogic()); + engine->rootContext()->setContextProperty("AppSettingsLogic", uiLogic->appSettingsLogic()); + engine->rootContext()->setContextProperty("GeneralSettingsLogic", uiLogic->generalSettingsLogic()); + engine->rootContext()->setContextProperty("NetworkSettingsLogic", uiLogic->networkSettingsLogic()); + engine->rootContext()->setContextProperty("ServerConfiguringProgressLogic", uiLogic->serverConfiguringProgressLogic()); + engine->rootContext()->setContextProperty("NewServerProtocolsLogic", uiLogic->newServerProtocolsLogic()); + engine->rootContext()->setContextProperty("ServerListLogic", uiLogic->serverListLogic()); + engine->rootContext()->setContextProperty("ServerSettingsLogic", uiLogic->serverSettingsLogic()); + engine->rootContext()->setContextProperty("ServerContainersLogic", uiLogic->serverVpnProtocolsLogic()); + engine->rootContext()->setContextProperty("ShareConnectionLogic", uiLogic->shareConnectionLogic()); + engine->rootContext()->setContextProperty("SitesLogic", uiLogic->sitesLogic()); + engine->rootContext()->setContextProperty("StartPageLogic", uiLogic->startPageLogic()); + engine->rootContext()->setContextProperty("VpnLogic", uiLogic->vpnLogic()); + engine->rootContext()->setContextProperty("WizardLogic", uiLogic->wizardLogic()); - engine.load(url); + engine->load(url); + + QObject::connect(&app, &QCoreApplication::aboutToQuit, uiLogic, [&engine, uiLogic](){ + QObject::disconnect(engine, 0,0,0); + delete engine; + + QObject::disconnect(uiLogic, 0,0,0); + delete uiLogic; + }); // TODO - fix //#ifdef Q_OS_WIN diff --git a/client/protocols/ikev2_vpn_protocol.cpp b/client/protocols/ikev2_vpn_protocol.cpp index f63e498e..ccb3c7ad 100644 --- a/client/protocols/ikev2_vpn_protocol.cpp +++ b/client/protocols/ikev2_vpn_protocol.cpp @@ -39,26 +39,15 @@ Ikev2Protocol::~Ikev2Protocol() void Ikev2Protocol::stop() { + setConnectionState(VpnProtocol::Disconnecting); #ifdef Q_OS_WINDOWS { - //setConnectionState(Disconnecting); - - //auto disconnectProcess = new QProcess; - - // disconnectProcess->setProgram("rasdial"); - // QString arguments = QString("\"%1\" /disconnect") - // .arg(tunnelName()); - // disconnectProcess->setNativeArguments(arguments); - - // // connect(connectProcess, &QProcess::readyRead, [connectProcess]() { - // // qDebug().noquote() << "connectProcess readyRead" << connectProcess->readAll(); - // // }); - - // disconnectProcess->start(); - // disconnectProcess->waitForFinished(5000); - // setConnectionState(Disconnected); if (! disconnect_vpn() ){ qDebug()<<"We don't disconnect"; + setConnectionState(VpnProtocol::Error); + } + else { + setConnectionState(VpnProtocol::Disconnected); } } #endif @@ -440,12 +429,11 @@ bool Ikev2Protocol::disconnect_vpn(){ if ( RasHangUp(hRasConn) != ERROR_SUCCESS) return false; } - std::this_thread::sleep_for(std::chrono::seconds(3)); + QThread::msleep(3000); + return true; } -#endif -#ifdef Q_OS_WINDOWS void WINAPI RasDialFuncCallback(UINT unMsg, RASCONNSTATE rasconnstate, DWORD dwError ){ diff --git a/client/ui/pages_logic/VpnLogic.cpp b/client/ui/pages_logic/VpnLogic.cpp index cc7884fc..b01407eb 100644 --- a/client/ui/pages_logic/VpnLogic.cpp +++ b/client/ui/pages_logic/VpnLogic.cpp @@ -24,6 +24,9 @@ VpnLogic::VpnLogic(UiLogic *logic, QObject *parent): connect(uiLogic()->m_vpnConnection, &VpnConnection::connectionStateChanged, this, &VpnLogic::onConnectionStateChanged); connect(uiLogic()->m_vpnConnection, &VpnConnection::vpnProtocolError, this, &VpnLogic::onVpnProtocolError); + connect(this, &VpnLogic::connectToVpn, uiLogic()->m_vpnConnection, &VpnConnection::connectToVpn, Qt::QueuedConnection); + connect(this, &VpnLogic::disconnectFromVpn, uiLogic()->m_vpnConnection, &VpnConnection::disconnectFromVpn, Qt::QueuedConnection); + if (m_settings.isAutoConnect() && m_settings.defaultServerIndex() >= 0) { QTimer::singleShot(1000, this, [this](){ set_pushButtonConnectEnabled(false); @@ -166,20 +169,19 @@ void VpnLogic::onConnectWorker(int serverIndex, const ServerCredentials &credent qApp->processEvents(); - ErrorCode errorCode = uiLogic()->m_vpnConnection->connectToVpn( - serverIndex, credentials, container, containerConfig); + emit connectToVpn(serverIndex, credentials, container, containerConfig); - if (errorCode) { - //ui->pushButton_connect->setChecked(false); - uiLogic()->setDialogConnectErrorText(errorString(errorCode)); - emit uiLogic()->showConnectErrorDialog(); - return; - } +// if (errorCode) { +// //ui->pushButton_connect->setChecked(false); +// uiLogic()->setDialogConnectErrorText(errorString(errorCode)); +// emit uiLogic()->showConnectErrorDialog(); +// return; +// } } void VpnLogic::onDisconnect() { set_pushButtonConnectChecked(false); - uiLogic()->m_vpnConnection->disconnectFromVpn(); + emit disconnectFromVpn(); } diff --git a/client/ui/pages_logic/VpnLogic.h b/client/ui/pages_logic/VpnLogic.h index cda57f6d..07146952 100644 --- a/client/ui/pages_logic/VpnLogic.h +++ b/client/ui/pages_logic/VpnLogic.h @@ -48,5 +48,10 @@ public slots: void onConnectionStateChanged(VpnProtocol::ConnectionState state); void onVpnProtocolError(amnezia::ErrorCode errorCode); +signals: + void connectToVpn(int serverIndex, + const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig); + + void disconnectFromVpn(); }; #endif // VPN_LOGIC_H diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index d1525a7f..4f94f7a0 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -77,7 +77,9 @@ UiLogic::UiLogic(QObject *parent) : { m_containersModel = new ContainersModel(this); m_protocolsModel = new ProtocolsModel(this); - m_vpnConnection = new VpnConnection(this); + m_vpnConnection = new VpnConnection(); + m_vpnConnection->moveToThread(&m_vpnConnectionThread); + m_vpnConnectionThread.start(); m_appSettingsLogic = new AppSettingsLogic(this); m_generalSettingsLogic = new GeneralSettingsLogic(this); @@ -264,16 +266,21 @@ void UiLogic::setDialogConnectErrorText(const QString &dialogConnectErrorText) UiLogic::~UiLogic() { - hide(); - m_vpnConnection->disconnectFromVpn(); - for (int i = 0; i < 50; i++) { - qApp->processEvents(QEventLoop::ExcludeUserInputEvents); - QThread::msleep(100); - if (m_vpnConnection->isDisconnected()) { - break; + emit hide(); + + if (m_vpnConnection->connectionState() != VpnProtocol::ConnectionState::Disconnected) { + m_vpnConnection->disconnectFromVpn(); + for (int i = 0; i < 50; i++) { + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + QThread::msleep(100); + if (m_vpnConnection->isDisconnected()) { + break; + } } } + m_vpnConnectionThread.quit(); + m_vpnConnectionThread.wait(3000); delete m_vpnConnection; qDebug() << "Application closed"; diff --git a/client/ui/uilogic.h b/client/ui/uilogic.h index 320f7af1..21ea7066 100644 --- a/client/ui/uilogic.h +++ b/client/ui/uilogic.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "property_helper.h" #include "pages.h" @@ -210,6 +211,7 @@ private: QMap m_protocolLogicMap; VpnConnection* m_vpnConnection; + QThread m_vpnConnectionThread; Settings m_settings; diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index 6169902b..456a8568 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -23,12 +23,7 @@ VpnConnection::VpnConnection(QObject* parent) : QObject(parent) { - QTimer::singleShot(0, this, [this](){ - if (!IpcClient::init()) { - qWarning() << "Error occured when init IPC client"; - emit serviceIsNotReady(); - } - }); + } VpnConnection::~VpnConnection() @@ -190,10 +185,6 @@ QJsonObject VpnConnection::createVpnConfiguration(int serverIndex, for (ProtocolEnumNS::Protocol proto : ContainerProps::protocolsForContainer(container)) { -// QString vpnConfigData = -// createVpnConfigurationForProto( -// serverIndex, credentials, container, containerConfig, proto, &e); - QJsonObject vpnConfigData = QJsonDocument::fromJson( createVpnConfigurationForProto( serverIndex, credentials, container, containerConfig, proto, &e).toUtf8()). @@ -205,7 +196,6 @@ QJsonObject VpnConnection::createVpnConfiguration(int serverIndex, } vpnConfiguration.insert(ProtocolProps::key_proto_config_data(proto), vpnConfigData); - } Protocol proto = ContainerProps::defaultProtocol(container); @@ -214,11 +204,27 @@ QJsonObject VpnConnection::createVpnConfiguration(int serverIndex, return vpnConfiguration; } -ErrorCode VpnConnection::connectToVpn(int serverIndex, +void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig) { qDebug() << QString("СonnectToVpn, Server index is %1, container is %2, route mode is") .arg(serverIndex).arg(ContainerProps::containerToString(container)) << m_settings.routeMode(); + + #if !defined (Q_OS_ANDROID) && !defined (Q_OS_IOS) + if (!m_IpcClient) { + m_IpcClient = new IpcClient; + } + + if (!m_IpcClient->isSocketConnected()) { + if (!IpcClient::init(m_IpcClient)) { + qWarning() << "Error occured when init IPC client"; + emit serviceIsNotReady(); + emit connectionStateChanged(VpnProtocol::Error); + return; + } + } +#endif + m_remoteAddress = credentials.hostName; emit connectionStateChanged(VpnProtocol::Connecting); @@ -233,26 +239,26 @@ ErrorCode VpnConnection::connectToVpn(int serverIndex, m_vpnConfiguration = createVpnConfiguration(serverIndex, credentials, container, containerConfig); if (e) { emit connectionStateChanged(VpnProtocol::Error); - return e; + return; } #ifndef Q_OS_ANDROID - m_vpnProtocol.reset(VpnProtocol::factory(container, m_vpnConfiguration)); if (!m_vpnProtocol) { - return ErrorCode::InternalError; + emit VpnProtocol::Error; + return; } m_vpnProtocol->prepare(); - #else Protocol proto = ContainerProps::defaultProtocol(container); AndroidVpnProtocol *androidVpnProtocol = new AndroidVpnProtocol(proto, m_vpnConfiguration); if (!androidVpnProtocol->initialize()) { qDebug() << QString("Init failed") ; - return UnknownError; + emit VpnProtocol::Error; + return; } m_vpnProtocol.reset(androidVpnProtocol); #endif @@ -263,7 +269,8 @@ ErrorCode VpnConnection::connectToVpn(int serverIndex, ServerController::disconnectFromHost(credentials); - return m_vpnProtocol.data()->start(); + e = m_vpnProtocol.data()->start(); + if (e) emit VpnProtocol::Error; } QString VpnConnection::bytesPerSecToText(quint64 bytes) diff --git a/client/vpnconnection.h b/client/vpnconnection.h index 5ad0ef94..9d0c3337 100644 --- a/client/vpnconnection.h +++ b/client/vpnconnection.h @@ -34,10 +34,7 @@ public: const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); - ErrorCode connectToVpn(int serverIndex, - const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig); - void disconnectFromVpn(); bool isConnected() const; bool isDisconnected() const; @@ -51,6 +48,12 @@ public: const QString &remoteAddress() const; +public slots: + void connectToVpn(int serverIndex, + const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig); + + void disconnectFromVpn(); + signals: void bytesChanged(quint64 receivedBytes, quint64 sentBytes); void connectionStateChanged(VpnProtocol::ConnectionState state); @@ -70,6 +73,7 @@ private: QJsonObject m_vpnConfiguration; QJsonObject m_routeMode; QString m_remoteAddress; + IpcClient *m_IpcClient {nullptr}; };