Fix disconnect bug
This commit is contained in:
parent
e7658f9859
commit
1e64413904
6 changed files with 40 additions and 43 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue