summaryrefslogtreecommitdiffhomepage
path: root/android/lib/common/src
diff options
context:
space:
mode:
Diffstat (limited to 'android/lib/common/src')
-rw-r--r--android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt46
1 files changed, 43 insertions, 3 deletions
diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt
index 59833cb396..06c862936b 100644
--- a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt
+++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt
@@ -2,10 +2,14 @@ package net.mullvad.mullvadvpn.lib.common.util
import android.content.Context
import android.content.Intent
+import android.net.VpnService
import android.net.VpnService.prepare
+import android.os.ParcelFileDescriptor
import arrow.core.Either
-import arrow.core.flatten
+import arrow.core.flatMap
import arrow.core.left
+import arrow.core.raise.either
+import arrow.core.raise.ensureNotNull
import arrow.core.right
import co.touchlab.kermit.Logger
import net.mullvad.mullvadvpn.lib.common.util.SdkUtils.getInstalledPackagesList
@@ -13,6 +17,8 @@ import net.mullvad.mullvadvpn.lib.model.PrepareError
import net.mullvad.mullvadvpn.lib.model.Prepared
/**
+ * Prepare to establish a VPN connection safely.
+ *
* Invoking VpnService.prepare() can result in 3 out comes:
* 1. IllegalStateException - There is a legacy VPN profile marked as always on
* 2. Intent
@@ -34,7 +40,7 @@ fun Context.prepareVpnSafe(): Either<PrepareError, Prepared> =
else -> throw it
}
}
- .map { intent ->
+ .flatMap { intent ->
if (intent == null) {
Prepared.right()
} else {
@@ -46,7 +52,6 @@ fun Context.prepareVpnSafe(): Either<PrepareError, Prepared> =
}
}
}
- .flatten()
fun Context.getAlwaysOnVpnAppName(): String? {
return resolveAlwaysOnVpnPackageName()
@@ -59,3 +64,38 @@ fun Context.getAlwaysOnVpnAppName(): String? {
?.loadLabel(packageManager)
?.toString()
}
+
+/**
+ * Establish a VPN connection safely.
+ *
+ * This function wraps the [VpnService.Builder.establish] function and catches any exceptions that
+ * may be thrown and type them to a more specific error.
+ *
+ * @return [ParcelFileDescriptor] if successful, [EstablishError] otherwise
+ */
+fun VpnService.Builder.establishSafe(): Either<EstablishError, ParcelFileDescriptor> = either {
+ val vpnInterfaceFd =
+ Either.catch { establish() }
+ .mapLeft {
+ when (it) {
+ is IllegalStateException -> EstablishError.ParameterNotApplied(it)
+ is IllegalArgumentException -> EstablishError.ParameterNotAccepted(it)
+ else -> EstablishError.UnknownError(it)
+ }
+ }
+ .bind()
+
+ ensureNotNull(vpnInterfaceFd) { EstablishError.NullVpnInterface }
+
+ vpnInterfaceFd
+}
+
+sealed interface EstablishError {
+ data class ParameterNotApplied(val exception: IllegalStateException) : EstablishError
+
+ data class ParameterNotAccepted(val exception: IllegalArgumentException) : EstablishError
+
+ data object NullVpnInterface : EstablishError
+
+ data class UnknownError(val error: Throwable) : EstablishError
+}