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

View file

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

View file

@ -3,7 +3,7 @@
#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)
{ }
@ -16,11 +16,6 @@ ErrorCode AndroidVpnProtocol::start()
void AndroidVpnProtocol::stop()
{
qDebug() << "AndroidVpnProtocol::stop()";
setConnectionState(Vpn::ConnectionState::Disconnecting);
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
public:
explicit AndroidVpnProtocol(Proto protocol, const QJsonObject& configuration, QObject* parent = nullptr);
explicit AndroidVpnProtocol(const QJsonObject& configuration, QObject* parent = nullptr);
~AndroidVpnProtocol() override = default;
ErrorCode start() override;
void stop() override;
public slots:
void connectionDataUpdated(quint64 rxBytes, quint64 txBytes);
};
#endif // ANDROID_VPNPROTOCOL_H

View file

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

View file

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