Fix disconnect bug

This commit is contained in:
albexk 2023-12-04 18:23:08 +03:00
parent e7658f9859
commit 1e64413904
6 changed files with 40 additions and 43 deletions

View file

@ -3,7 +3,10 @@ package org.amnezia.vpn.protocol.openvpn
import android.content.Context import android.content.Context
import android.net.VpnService.Builder import android.net.VpnService.Builder
import android.os.Build import android.os.Build
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import net.openvpn.ovpn3.ClientAPI_Config import net.openvpn.ovpn3.ClientAPI_Config
import org.amnezia.vpn.protocol.BadConfigException import org.amnezia.vpn.protocol.BadConfigException
import org.amnezia.vpn.protocol.Protocol import org.amnezia.vpn.protocol.Protocol
@ -35,7 +38,8 @@ import org.json.JSONObject
open class OpenVpn : Protocol() { open class OpenVpn : Protocol() {
private lateinit var context: Context private lateinit var context: Context
protected var openVpnClient: OpenVpnClient? = null private var openVpnClient: OpenVpnClient? = null
private lateinit var scope: CoroutineScope
override val statistics: Statistics override val statistics: Statistics
get() { get() {
@ -53,6 +57,7 @@ open class OpenVpn : Protocol() {
super.initialize(context, state) super.initialize(context, state)
loadSharedLibrary(context, "ovpn3") loadSharedLibrary(context, "ovpn3")
this.context = context this.context = context
scope = CoroutineScope(Dispatchers.IO)
} }
override fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) { override fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
@ -84,11 +89,13 @@ open class OpenVpn : Protocol() {
configSplitTunnel(config) configSplitTunnel(config)
} }
scope.launch {
val status = client.connect() val status = client.connect()
if (status.error) { if (status.error) {
throw VpnException("OpenVpn connect() error: ${status.status}: ${status.message}") throw VpnException("OpenVpn connect() error: ${status.status}: ${status.message}")
} }
} }
}
} catch (e: Exception) { } catch (e: Exception) {
openVpnClient = null openVpnClient = null
throw e throw e

View file

@ -22,10 +22,11 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeoutOrNull
import org.amnezia.vpn.protocol.BadConfigException import org.amnezia.vpn.protocol.BadConfigException
import org.amnezia.vpn.protocol.LoadLibraryException import org.amnezia.vpn.protocol.LoadLibraryException
import org.amnezia.vpn.protocol.Protocol import org.amnezia.vpn.protocol.Protocol
@ -56,6 +57,7 @@ const val AFTER_PERMISSION_CHECK = "AFTER_PERMISSION_CHECK"
private const val PREFS_CONFIG_KEY = "LAST_CONF" private const val PREFS_CONFIG_KEY = "LAST_CONF"
private const val NOTIFICATION_ID = 1337 private const val NOTIFICATION_ID = 1337
private const val STATISTICS_SENDING_TIMEOUT = 1000L private const val STATISTICS_SENDING_TIMEOUT = 1000L
private const val DISCONNECT_TIMEOUT = 1500L
class AmneziaVpnService : VpnService() { class AmneziaVpnService : VpnService() {
@ -227,8 +229,12 @@ class AmneziaVpnService : VpnService() {
override fun onDestroy() { override fun onDestroy() {
Log.v(TAG, "Destroy service") Log.v(TAG, "Destroy service")
// todo: add sync disconnect runBlocking {
withTimeoutOrNull(DISCONNECT_TIMEOUT) {
disconnect() disconnect()
disconnectionJob?.join()
}
}
connectionScope.cancel() connectionScope.cancel()
mainScope.cancel() mainScope.cancel()
super.onDestroy() super.onDestroy()
@ -322,9 +328,7 @@ class AmneziaVpnService : VpnService() {
protocolState.value = DISCONNECTING protocolState.value = DISCONNECTING
disconnectionJob = connectionScope.launch { disconnectionJob = connectionScope.launch {
connectionJob?.let { connectionJob?.join()
if (it.isActive) it.cancelAndJoin()
}
connectionJob = null connectionJob = null
protocol?.stopVpn() protocol?.stopVpn()
@ -342,6 +346,7 @@ class AmneziaVpnService : VpnService() {
"cloak" -> Cloak() "cloak" -> Cloak()
else -> throw IllegalArgumentException("Protocol '$protocolName' not found") else -> throw IllegalArgumentException("Protocol '$protocolName' not found")
}.apply { initialize(applicationContext, protocolState) } }.apply { initialize(applicationContext, protocolState) }
.also { protocolCache[protocolName] = it }
/** /**
* Utils methods * Utils methods

View file

@ -3,7 +3,7 @@
#include "platforms/android/android_controller.h" #include "platforms/android/android_controller.h"
AndroidVpnProtocol::AndroidVpnProtocol(Proto protocol, const QJsonObject &configuration, QObject* parent) AndroidVpnProtocol::AndroidVpnProtocol(const QJsonObject &configuration, QObject* parent)
: VpnProtocol(configuration, parent) : VpnProtocol(configuration, parent)
{ } { }
@ -16,11 +16,6 @@ ErrorCode AndroidVpnProtocol::start()
void AndroidVpnProtocol::stop() void AndroidVpnProtocol::stop()
{ {
qDebug() << "AndroidVpnProtocol::stop()"; qDebug() << "AndroidVpnProtocol::stop()";
setConnectionState(Vpn::ConnectionState::Disconnecting);
AndroidController::instance()->stop(); AndroidController::instance()->stop();
} }
void AndroidVpnProtocol::connectionDataUpdated(quint64 rxBytes, quint64 txBytes)
{
setBytesChanged(rxBytes, txBytes);
}

View file

@ -10,15 +10,11 @@ class AndroidVpnProtocol : public VpnProtocol
Q_OBJECT Q_OBJECT
public: public:
explicit AndroidVpnProtocol(Proto protocol, const QJsonObject& configuration, QObject* parent = nullptr); explicit AndroidVpnProtocol(const QJsonObject& configuration, QObject* parent = nullptr);
~AndroidVpnProtocol() override = default; ~AndroidVpnProtocol() override = default;
ErrorCode start() override; ErrorCode start() override;
void stop() override; void stop() override;
public slots:
void connectionDataUpdated(quint64 rxBytes, quint64 txBytes);
}; };
#endif // ANDROID_VPNPROTOCOL_H #endif // ANDROID_VPNPROTOCOL_H

View file

@ -19,7 +19,7 @@
#endif #endif
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
#include "../../platforms/android/android_controller.h" #include "platforms/android/android_controller.h"
#endif #endif
#ifdef Q_OS_IOS #ifdef Q_OS_IOS
@ -339,8 +339,8 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
} }
m_vpnProtocol->prepare(); m_vpnProtocol->prepare();
#elif defined Q_OS_ANDROID #elif defined Q_OS_ANDROID
androidVpnProtocol = createDefaultAndroidVpnProtocol(container); androidVpnProtocol = createDefaultAndroidVpnProtocol();
createAndroidConnections(container); createAndroidConnections();
m_vpnProtocol.reset(androidVpnProtocol); m_vpnProtocol.reset(androidVpnProtocol);
#elif defined Q_OS_IOS #elif defined Q_OS_IOS
@ -397,28 +397,17 @@ void VpnConnection::restoreConnection()
void VpnConnection::createAndroidConnections() void VpnConnection::createAndroidConnections()
{ {
int serverIndex = m_settings->defaultServerIndex(); androidVpnProtocol = createDefaultAndroidVpnProtocol();
DockerContainer container = m_settings->defaultContainer(serverIndex);
createAndroidConnections(container);
}
void VpnConnection::createAndroidConnections(DockerContainer container)
{
androidVpnProtocol = createDefaultAndroidVpnProtocol(container);
connect(AndroidController::instance(), &AndroidController::connectionStateChanged, androidVpnProtocol, connect(AndroidController::instance(), &AndroidController::connectionStateChanged, androidVpnProtocol,
&AndroidVpnProtocol::setConnectionState); &AndroidVpnProtocol::setConnectionState);
connect(AndroidController::instance(), &AndroidController::statisticsUpdated, androidVpnProtocol, connect(AndroidController::instance(), &AndroidController::statisticsUpdated, androidVpnProtocol,
&AndroidVpnProtocol::connectionDataUpdated); &AndroidVpnProtocol::setBytesChanged);
} }
AndroidVpnProtocol *VpnConnection::createDefaultAndroidVpnProtocol(DockerContainer container) AndroidVpnProtocol *VpnConnection::createDefaultAndroidVpnProtocol()
{ {
Proto proto = ContainerProps::defaultProtocol(container); return new AndroidVpnProtocol(m_vpnConfiguration);
AndroidVpnProtocol *androidVpnProtocol = new AndroidVpnProtocol(proto, m_vpnConfiguration);
return androidVpnProtocol;
} }
#endif #endif
@ -441,7 +430,13 @@ void VpnConnection::disconnectFromVpn()
#endif #endif
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
AndroidController::instance()->stop(); if (m_vpnProtocol && m_vpnProtocol.data()) {
connect(AndroidController::instance(), &AndroidController::vpnDisconnected, this,
[this]() {
onConnectionStateChanged(Vpn::ConnectionState::Disconnected);
}, Qt::SingleShotConnection);
m_vpnProtocol.data()->stop();
}
#endif #endif
#ifdef Q_OS_IOS #ifdef Q_OS_IOS

View file

@ -106,9 +106,8 @@ private:
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
AndroidVpnProtocol* androidVpnProtocol = nullptr; AndroidVpnProtocol* androidVpnProtocol = nullptr;
AndroidVpnProtocol* createDefaultAndroidVpnProtocol(DockerContainer container); AndroidVpnProtocol* createDefaultAndroidVpnProtocol();
void createAndroidConnections(); void createAndroidConnections();
void createAndroidConnections(DockerContainer container);
#endif #endif
void createProtocolConnections(); void createProtocolConnections();