summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectActionButton.kt24
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt4
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectionStatus.kt14
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/HeaderBar.kt14
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt8
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/NotificationBanner.kt14
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/SwitchLocationButton.kt14
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/ConnectionProxy.kt18
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/LocationInfoCache.kt24
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelState.kt9
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelStateTransition.kt9
-rw-r--r--gui/src/main/daemon-rpc.ts37
-rw-r--r--gui/src/main/index.ts43
-rw-r--r--gui/src/main/notification-controller.ts4
-rw-r--r--gui/src/renderer/app.tsx15
-rw-r--r--gui/src/renderer/components/NotificationArea.tsx4
-rw-r--r--gui/src/renderer/components/TunnelControl.tsx4
-rw-r--r--gui/src/renderer/containers/ConnectionPanelContainer.tsx4
-rw-r--r--gui/src/renderer/redux/connection/actions.ts14
-rw-r--r--gui/src/renderer/redux/connection/reducers.ts8
-rw-r--r--gui/src/shared/daemon-rpc-types.ts15
-rw-r--r--gui/src/shared/ipc-event-channel.ts8
-rw-r--r--gui/test/components/NotificationArea.spec.tsx14
-rw-r--r--mullvad-cli/src/cmds/status.rs20
-rw-r--r--mullvad-daemon/src/lib.rs60
-rw-r--r--mullvad-daemon/src/management_interface.rs14
-rw-r--r--mullvad-ipc-client/src/lib.rs5
-rw-r--r--mullvad-jni/src/daemon_interface.rs13
-rw-r--r--mullvad-jni/src/into_java.rs19
-rw-r--r--mullvad-jni/src/jni_event_listener.rs18
-rw-r--r--mullvad-jni/src/lib.rs10
-rw-r--r--mullvad-types/src/lib.rs2
-rw-r--r--mullvad-types/src/location.rs2
-rw-r--r--mullvad-types/src/states.rs33
34 files changed, 296 insertions, 222 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectActionButton.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectActionButton.kt
index faf4a61521..a430ab84c7 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectActionButton.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectActionButton.kt
@@ -3,19 +3,19 @@ package net.mullvad.mullvadvpn
import android.view.View
import android.widget.Button
-import net.mullvad.mullvadvpn.model.TunnelStateTransition
+import net.mullvad.mullvadvpn.model.TunnelState
class ConnectActionButton(val parentView: View) {
private val button: Button = parentView.findViewById(R.id.action_button)
- var state: TunnelStateTransition = TunnelStateTransition.Disconnected()
+ var state: TunnelState = TunnelState.Disconnected()
set(value) {
when (value) {
- is TunnelStateTransition.Disconnected -> disconnected()
- is TunnelStateTransition.Disconnecting -> disconnected()
- is TunnelStateTransition.Connecting -> connecting()
- is TunnelStateTransition.Connected -> connected()
- is TunnelStateTransition.Blocked -> connected()
+ is TunnelState.Disconnected -> disconnected()
+ is TunnelState.Disconnecting -> disconnected()
+ is TunnelState.Connecting -> connecting()
+ is TunnelState.Connected -> connected()
+ is TunnelState.Blocked -> connected()
}
field = value
@@ -31,11 +31,11 @@ class ConnectActionButton(val parentView: View) {
private fun action() {
when (state) {
- is TunnelStateTransition.Disconnected -> onConnect?.invoke()
- is TunnelStateTransition.Disconnecting -> onConnect?.invoke()
- is TunnelStateTransition.Connecting -> onCancel?.invoke()
- is TunnelStateTransition.Connected -> onDisconnect?.invoke()
- is TunnelStateTransition.Blocked -> onDisconnect?.invoke()
+ is TunnelState.Disconnected -> onConnect?.invoke()
+ is TunnelState.Disconnecting -> onConnect?.invoke()
+ is TunnelState.Connecting -> onCancel?.invoke()
+ is TunnelState.Connected -> onDisconnect?.invoke()
+ is TunnelState.Blocked -> onDisconnect?.invoke()
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt
index 53e00a4c31..9a7c50a9af 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt
@@ -16,7 +16,7 @@ import android.widget.ImageButton
import net.mullvad.mullvadvpn.dataproxy.ConnectionProxy
import net.mullvad.mullvadvpn.dataproxy.LocationInfoCache
import net.mullvad.mullvadvpn.dataproxy.RelayListListener
-import net.mullvad.mullvadvpn.model.TunnelStateTransition
+import net.mullvad.mullvadvpn.model.TunnelState
class ConnectFragment : Fragment() {
private lateinit var actionButton: ConnectActionButton
@@ -104,7 +104,7 @@ class ConnectFragment : Fragment() {
super.onDestroyView()
}
- private fun updateView(uiState: TunnelStateTransition) {
+ private fun updateView(uiState: TunnelState) {
val realState = connectionProxy.state
locationInfoCache.state = realState
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectionStatus.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectionStatus.kt
index 652eae4da5..fda8eee4bc 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectionStatus.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectionStatus.kt
@@ -4,7 +4,7 @@ import android.content.Context
import android.view.View
import android.widget.TextView
-import net.mullvad.mullvadvpn.model.TunnelStateTransition
+import net.mullvad.mullvadvpn.model.TunnelState
class ConnectionStatus(val parentView: View, val context: Context) {
private val spinner: View = parentView.findViewById(R.id.connecting_spinner)
@@ -14,13 +14,13 @@ class ConnectionStatus(val parentView: View, val context: Context) {
private val connectingTextColor = context.getColor(R.color.white)
private val connectedTextColor = context.getColor(R.color.green)
- fun setState(state: TunnelStateTransition) {
+ fun setState(state: TunnelState) {
when (state) {
- is TunnelStateTransition.Disconnecting -> disconnected()
- is TunnelStateTransition.Disconnected -> disconnected()
- is TunnelStateTransition.Connecting -> connecting()
- is TunnelStateTransition.Connected -> connected()
- is TunnelStateTransition.Blocked -> connected()
+ is TunnelState.Disconnecting -> disconnected()
+ is TunnelState.Disconnected -> disconnected()
+ is TunnelState.Connecting -> connecting()
+ is TunnelState.Connected -> connected()
+ is TunnelState.Blocked -> connected()
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/HeaderBar.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/HeaderBar.kt
index 6988dae839..f965d82711 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/HeaderBar.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/HeaderBar.kt
@@ -3,7 +3,7 @@ package net.mullvad.mullvadvpn
import android.content.Context
import android.view.View
-import net.mullvad.mullvadvpn.model.TunnelStateTransition
+import net.mullvad.mullvadvpn.model.TunnelState
class HeaderBar(val parentView: View, val context: Context) {
private val headerBar: View = parentView.findViewById(R.id.header_bar)
@@ -11,13 +11,13 @@ class HeaderBar(val parentView: View, val context: Context) {
private val securedColor = context.getColor(R.color.green)
private val unsecuredColor = context.getColor(R.color.red)
- fun setState(state: TunnelStateTransition) {
+ fun setState(state: TunnelState) {
when (state) {
- is TunnelStateTransition.Disconnected -> unsecured()
- is TunnelStateTransition.Connecting -> secured()
- is TunnelStateTransition.Connected -> secured()
- is TunnelStateTransition.Disconnecting -> secured()
- is TunnelStateTransition.Blocked -> secured()
+ is TunnelState.Disconnected -> unsecured()
+ is TunnelState.Connecting -> secured()
+ is TunnelState.Connected -> secured()
+ is TunnelState.Disconnecting -> secured()
+ is TunnelState.Blocked -> secured()
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt
index 7033f13de7..eacedcdb69 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt
@@ -6,7 +6,7 @@ import net.mullvad.mullvadvpn.model.PublicKey
import net.mullvad.mullvadvpn.model.RelayList
import net.mullvad.mullvadvpn.model.RelaySettingsUpdate
import net.mullvad.mullvadvpn.model.Settings
-import net.mullvad.mullvadvpn.model.TunnelStateTransition
+import net.mullvad.mullvadvpn.model.TunnelState
class MullvadDaemon(val vpnService: MullvadVpnService) {
init {
@@ -16,7 +16,7 @@ class MullvadDaemon(val vpnService: MullvadVpnService) {
var onRelayListChange: ((RelayList) -> Unit)? = null
var onSettingsChange: ((Settings) -> Unit)? = null
- var onTunnelStateChange: ((TunnelStateTransition) -> Unit)? = null
+ var onTunnelStateChange: ((TunnelState) -> Unit)? = null
external fun connect()
external fun disconnect()
@@ -25,7 +25,7 @@ class MullvadDaemon(val vpnService: MullvadVpnService) {
external fun getCurrentLocation(): GeoIpLocation?
external fun getRelayLocations(): RelayList
external fun getSettings(): Settings
- external fun getState(): TunnelStateTransition
+ external fun getState(): TunnelState
external fun getWireguardKey(): PublicKey?
external fun setAccount(accountToken: String?)
external fun updateRelaySettings(update: RelaySettingsUpdate)
@@ -40,7 +40,7 @@ class MullvadDaemon(val vpnService: MullvadVpnService) {
onSettingsChange?.invoke(settings)
}
- private fun notifyTunnelStateEvent(event: TunnelStateTransition) {
+ private fun notifyTunnelStateEvent(event: TunnelState) {
onTunnelStateChange?.invoke(event)
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/NotificationBanner.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/NotificationBanner.kt
index 7789d57435..1af739dcc6 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/NotificationBanner.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/NotificationBanner.kt
@@ -2,19 +2,19 @@ package net.mullvad.mullvadvpn
import android.view.View
-import net.mullvad.mullvadvpn.model.TunnelStateTransition
+import net.mullvad.mullvadvpn.model.TunnelState
class NotificationBanner(val parentView: View) {
private val banner: View = parentView.findViewById(R.id.notification_banner)
private var visible = false
- fun setState(state: TunnelStateTransition) {
+ fun setState(state: TunnelState) {
when (state) {
- is TunnelStateTransition.Disconnecting -> hide()
- is TunnelStateTransition.Disconnected -> hide()
- is TunnelStateTransition.Connecting -> show()
- is TunnelStateTransition.Connected -> hide()
- is TunnelStateTransition.Blocked -> show()
+ is TunnelState.Disconnecting -> hide()
+ is TunnelState.Disconnected -> hide()
+ is TunnelState.Connecting -> show()
+ is TunnelState.Connected -> hide()
+ is TunnelState.Blocked -> show()
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/SwitchLocationButton.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/SwitchLocationButton.kt
index 4c89bc259e..d35374b29e 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/SwitchLocationButton.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/SwitchLocationButton.kt
@@ -9,7 +9,7 @@ import android.graphics.drawable.Drawable
import android.view.View
import android.widget.Button
-import net.mullvad.mullvadvpn.model.TunnelStateTransition
+import net.mullvad.mullvadvpn.model.TunnelState
import net.mullvad.mullvadvpn.relaylist.RelayItem
class SwitchLocationButton(val parentView: View) {
@@ -24,7 +24,7 @@ class SwitchLocationButton(val parentView: View) {
update()
}
- var state: TunnelStateTransition = TunnelStateTransition.Disconnected()
+ var state: TunnelState = TunnelState.Disconnected()
set(value) {
field = value
update()
@@ -44,11 +44,11 @@ class SwitchLocationButton(val parentView: View) {
updateJob?.cancel()
updateJob = GlobalScope.launch(Dispatchers.Main) {
when (state) {
- is TunnelStateTransition.Disconnected -> showLocation()
- is TunnelStateTransition.Disconnecting -> showLocation()
- is TunnelStateTransition.Connecting -> showLabel()
- is TunnelStateTransition.Connected -> showLabel()
- is TunnelStateTransition.Blocked -> showLocation()
+ is TunnelState.Disconnected -> showLocation()
+ is TunnelState.Disconnecting -> showLocation()
+ is TunnelState.Connecting -> showLabel()
+ is TunnelState.Connected -> showLabel()
+ is TunnelState.Blocked -> showLocation()
}
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/ConnectionProxy.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/ConnectionProxy.kt
index fb74e70160..8922344de5 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/ConnectionProxy.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/ConnectionProxy.kt
@@ -6,7 +6,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import net.mullvad.mullvadvpn.MainActivity
-import net.mullvad.mullvadvpn.model.TunnelStateTransition
+import net.mullvad.mullvadvpn.model.TunnelState
class ConnectionProxy(val parentActivity: MainActivity) {
val daemon = parentActivity.daemon
@@ -16,27 +16,27 @@ class ConnectionProxy(val parentActivity: MainActivity) {
private val attachListenerJob = attachListener()
private val fetchInitialStateJob = fetchInitialState()
- private var realState: TunnelStateTransition? = null
+ private var realState: TunnelState? = null
set(value) {
field = value
- uiState = value ?: TunnelStateTransition.Disconnected()
+ uiState = value ?: TunnelState.Disconnected()
}
- val state: TunnelStateTransition
+ val state: TunnelState
get() {
- return realState ?: TunnelStateTransition.Disconnected()
+ return realState ?: TunnelState.Disconnected()
}
- var uiState: TunnelStateTransition = TunnelStateTransition.Disconnected()
+ var uiState: TunnelState = TunnelState.Disconnected()
private set(value) {
field = value
onUiStateChange?.invoke(value)
}
- var onUiStateChange: ((TunnelStateTransition) -> Unit)? = null
+ var onUiStateChange: ((TunnelState) -> Unit)? = null
fun connect() {
- uiState = TunnelStateTransition.Connecting()
+ uiState = TunnelState.Connecting()
cancelActiveAction()
@@ -50,7 +50,7 @@ class ConnectionProxy(val parentActivity: MainActivity) {
}
fun disconnect() {
- uiState = TunnelStateTransition.Disconnecting()
+ uiState = TunnelState.Disconnecting()
cancelActiveAction()
activeAction = GlobalScope.launch(Dispatchers.Default) {
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/LocationInfoCache.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/LocationInfoCache.kt
index 4f5684b157..9b39853d25 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/LocationInfoCache.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/LocationInfoCache.kt
@@ -8,7 +8,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import net.mullvad.mullvadvpn.model.GeoIpLocation
-import net.mullvad.mullvadvpn.model.TunnelStateTransition
+import net.mullvad.mullvadvpn.model.TunnelState
import net.mullvad.mullvadvpn.MullvadDaemon
class LocationInfoCache(val daemon: Deferred<MullvadDaemon>) {
@@ -27,16 +27,16 @@ class LocationInfoCache(val daemon: Deferred<MullvadDaemon>) {
notifyNewLocation()
}
- var state: TunnelStateTransition = TunnelStateTransition.Disconnected()
+ var state: TunnelState = TunnelState.Disconnected()
set(value) {
field = value
when (value) {
- is TunnelStateTransition.Disconnected -> fetchLocation()
- is TunnelStateTransition.Connecting -> fetchLocation()
- is TunnelStateTransition.Connected -> fetchLocation()
- is TunnelStateTransition.Disconnecting -> location = lastKnownRealLocation
- is TunnelStateTransition.Blocked -> location = null
+ is TunnelState.Disconnected -> fetchLocation()
+ is TunnelState.Connecting -> fetchLocation()
+ is TunnelState.Connected -> fetchLocation()
+ is TunnelState.Disconnecting -> location = lastKnownRealLocation
+ is TunnelState.Blocked -> location = null
}
}
@@ -64,12 +64,12 @@ class LocationInfoCache(val daemon: Deferred<MullvadDaemon>) {
if (newLocation != null && state == initialState) {
when (state) {
- is TunnelStateTransition.Disconnected -> {
+ is TunnelState.Disconnected -> {
lastKnownRealLocation = newLocation
location = newLocation
}
- is TunnelStateTransition.Connecting -> location = newLocation
- is TunnelStateTransition.Connected -> location = newLocation
+ is TunnelState.Connecting -> location = newLocation
+ is TunnelState.Connected -> location = newLocation
}
}
}
@@ -82,7 +82,7 @@ class LocationInfoCache(val daemon: Deferred<MullvadDaemon>) {
private fun shouldRetryFetch(): Boolean {
val state = this.state
- return state is TunnelStateTransition.Disconnected ||
- state is TunnelStateTransition.Connected
+ return state is TunnelState.Disconnected ||
+ state is TunnelState.Connected
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelState.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelState.kt
new file mode 100644
index 0000000000..006de053c8
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelState.kt
@@ -0,0 +1,9 @@
+package net.mullvad.mullvadvpn.model
+
+sealed class TunnelState() {
+ class Disconnected() : TunnelState()
+ class Connecting() : TunnelState()
+ class Connected() : TunnelState()
+ class Disconnecting() : TunnelState()
+ class Blocked() : TunnelState()
+}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelStateTransition.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelStateTransition.kt
deleted file mode 100644
index ec65037e42..0000000000
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelStateTransition.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.mullvad.mullvadvpn.model
-
-sealed class TunnelStateTransition() {
- class Disconnected() : TunnelStateTransition()
- class Connecting() : TunnelStateTransition()
- class Connected() : TunnelStateTransition()
- class Disconnecting() : TunnelStateTransition()
- class Blocked() : TunnelStateTransition()
-}
diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts
index 215807b2a7..2c467a0d05 100644
--- a/gui/src/main/daemon-rpc.ts
+++ b/gui/src/main/daemon-rpc.ts
@@ -8,7 +8,7 @@ import {
IRelayList,
ISettings,
RelaySettingsUpdate,
- TunnelStateTransition,
+ TunnelState,
} from '../shared/daemon-rpc-types';
import { CommunicationError, InvalidAccountError, NoDaemonError } from './errors';
import JsonRpcClient, {
@@ -230,24 +230,27 @@ const accountDataSchema = partialObject({
expiry: string,
});
-const tunnelStateTransitionSchema = oneOf(
+const tunnelStateSchema = oneOf(
object({
state: enumeration('disconnecting'),
details: enumeration('nothing', 'block', 'reconnect'),
}),
object({
state: enumeration('connecting', 'connected'),
- details: partialObject({
- address: string,
- protocol: enumeration('tcp', 'udp'),
- tunnel_type: enumeration('wireguard', 'openvpn'),
- proxy: maybe(
- partialObject({
- address: string,
- protocol: enumeration('tcp', 'udp'),
- proxy_type: enumeration('shadowsocks', 'custom'),
- }),
- ),
+ details: object({
+ endpoint: partialObject({
+ address: string,
+ protocol: enumeration('tcp', 'udp'),
+ tunnel_type: enumeration('wireguard', 'openvpn'),
+ proxy: maybe(
+ partialObject({
+ address: string,
+ protocol: enumeration('tcp', 'udp'),
+ proxy_type: enumeration('shadowsocks', 'custom'),
+ }),
+ ),
+ }),
+ location: locationSchema,
}),
}),
object({
@@ -329,7 +332,7 @@ const settingsSchema = partialObject({
const daemonEventSchema = oneOf(
object({
- state_transition: tunnelStateTransitionSchema,
+ tunnel_state: tunnelStateSchema,
}),
object({
settings: settingsSchema,
@@ -468,12 +471,10 @@ export class DaemonRpc {
}
}
- public async getState(): Promise<TunnelStateTransition> {
+ public async getState(): Promise<TunnelState> {
const response = await this.transport.send('get_state');
try {
- return camelCaseObjectKeys(
- validate(tunnelStateTransitionSchema, response),
- ) as TunnelStateTransition;
+ return camelCaseObjectKeys(validate(tunnelStateSchema, response)) as TunnelState;
} catch (error) {
throw new ResponseParseError('Invalid response from get_state', error);
}
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts
index b34cc87fbc..9013c7c5cd 100644
--- a/gui/src/main/index.ts
+++ b/gui/src/main/index.ts
@@ -15,7 +15,7 @@ import {
ISettings,
RelaySettings,
RelaySettingsUpdate,
- TunnelStateTransition,
+ TunnelState,
} from '../shared/daemon-rpc-types';
import { loadTranslations, messages } from '../shared/gettext';
import { IpcMainEventChannel } from '../shared/ipc-event-channel';
@@ -73,7 +73,7 @@ class ApplicationMain {
private quitStage = AppQuitStage.unready;
private accountHistory: AccountToken[] = [];
- private tunnelState: TunnelStateTransition = { state: 'disconnected' };
+ private tunnelState: TunnelState = { state: 'disconnected' };
private settings: ISettings = {
accountToken: undefined,
allowLan: false,
@@ -480,8 +480,8 @@ class ApplicationMain {
private async subscribeEvents(): Promise<void> {
const daemonEventListener = new SubscriptionListener(
(daemonEvent: DaemonEvent) => {
- if ('stateTransition' in daemonEvent) {
- this.setTunnelState(daemonEvent.stateTransition);
+ if ('tunnelState' in daemonEvent) {
+ this.setTunnelState(daemonEvent.tunnelState);
} else if ('settings' in daemonEvent) {
this.setSettings(daemonEvent.settings);
} else if ('relayList' in daemonEvent) {
@@ -512,7 +512,7 @@ class ApplicationMain {
}
}
- private setTunnelState(newState: TunnelStateTransition) {
+ private setTunnelState(newState: TunnelState) {
this.tunnelState = newState;
this.updateTrayIcon(newState, this.settings.blockWhenDisconnected);
this.updateLocation();
@@ -724,16 +724,24 @@ class ApplicationMain {
}
private async updateLocation() {
- const state = this.tunnelState.state;
+ const tunnelState = this.tunnelState;
- if (state === 'connected' || state === 'disconnected' || state === 'connecting') {
- try {
- // It may take some time to fetch the new user location.
- // So take the user to the last known location when disconnected.
- if (state === 'disconnected' && this.lastDisconnectedLocation) {
- this.setLocation(this.lastDisconnectedLocation);
- }
+ if (tunnelState.state === 'connected' || tunnelState.state === 'connecting') {
+ // Location was broadcasted with the tunnel state, but it doesn't contain the relay out IP
+ // address, so it will have to be fetched afterwards
+ if (tunnelState.details) {
+ this.setLocation(tunnelState.details.location);
+ }
+ } else if (tunnelState.state === 'disconnected') {
+ // It may take some time to fetch the new user location.
+ // So take the user to the last known location when disconnected.
+ if (this.lastDisconnectedLocation) {
+ this.setLocation(this.lastDisconnectedLocation);
+ }
+ }
+ if (tunnelState.state === 'connected' || tunnelState.state === 'disconnected') {
+ try {
// Fetch the new user location
const location = await this.daemonRpc.getLocation();
// If the location is currently unavailable, do nothing! This only ever
@@ -751,7 +759,7 @@ class ApplicationMain {
// Broadcast the new location.
// There is a chance that the location is not stale if the tunnel state before the location
// request is the same as after receiving the response.
- if (this.tunnelState.state === state) {
+ if (this.tunnelState.state === tunnelState.state) {
this.setLocation(location);
}
} catch (error) {
@@ -760,10 +768,7 @@ class ApplicationMain {
}
}
- private trayIconType(
- tunnelState: TunnelStateTransition,
- blockWhenDisconnected: boolean,
- ): TrayIconType {
+ private trayIconType(tunnelState: TunnelState, blockWhenDisconnected: boolean): TrayIconType {
switch (tunnelState.state) {
case 'connected':
return 'secured';
@@ -791,7 +796,7 @@ class ApplicationMain {
}
}
- private updateTrayIcon(tunnelState: TunnelStateTransition, blockWhenDisconnected: boolean) {
+ private updateTrayIcon(tunnelState: TunnelState, blockWhenDisconnected: boolean) {
const type = this.trayIconType(tunnelState, blockWhenDisconnected);
if (this.trayIconController) {
diff --git a/gui/src/main/notification-controller.ts b/gui/src/main/notification-controller.ts
index a2e1e00a0b..771e788722 100644
--- a/gui/src/main/notification-controller.ts
+++ b/gui/src/main/notification-controller.ts
@@ -2,7 +2,7 @@ import { app, nativeImage, NativeImage, Notification, shell } from 'electron';
import path from 'path';
import { sprintf } from 'sprintf-js';
import config from '../config.json';
-import { TunnelStateTransition } from '../shared/daemon-rpc-types';
+import { TunnelState } from '../shared/daemon-rpc-types';
import { messages } from '../shared/gettext';
export default class NotificationController {
@@ -22,7 +22,7 @@ export default class NotificationController {
}
}
- public notifyTunnelState(tunnelState: TunnelStateTransition) {
+ public notifyTunnelState(tunnelState: TunnelState) {
switch (tunnelState.state) {
case 'connecting':
if (!this.reconnecting) {
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx
index ec7ba833e8..3d5a6eb0e5 100644
--- a/gui/src/renderer/app.tsx
+++ b/gui/src/renderer/app.tsx
@@ -38,7 +38,7 @@ import {
ISettings,
RelaySettings,
RelaySettingsUpdate,
- TunnelStateTransition,
+ TunnelState,
} from '../shared/daemon-rpc-types';
type AccountVerification = { status: 'verified' } | { status: 'deferred'; error: Error };
@@ -70,7 +70,7 @@ export default class AppRenderer {
);
private locale: string;
- private tunnelState: TunnelStateTransition;
+ private tunnelState: TunnelState;
private settings: ISettings;
private guiSettings: IGuiSettingsState;
private accountExpiry?: AccountExpiry;
@@ -109,7 +109,7 @@ export default class AppRenderer {
this.setAccountHistory(newAccountHistory);
});
- IpcRendererEventChannel.tunnel.listen((newState: TunnelStateTransition) => {
+ IpcRendererEventChannel.tunnel.listen((newState: TunnelState) => {
this.setTunnelState(newState);
this.updateBlockedState(newState, this.settings.blockWhenDisconnected);
@@ -461,7 +461,7 @@ export default class AppRenderer {
this.reduxActions.account.updateAccountHistory(accountHistory);
}
- private setTunnelState(tunnelState: TunnelStateTransition) {
+ private setTunnelState(tunnelState: TunnelState) {
const actions = this.reduxActions;
log.debug(`Tunnel state: ${tunnelState.state}`);
@@ -513,7 +513,7 @@ export default class AppRenderer {
}
}
- private updateBlockedState(tunnelState: TunnelStateTransition, blockWhenDisconnected: boolean) {
+ private updateBlockedState(tunnelState: TunnelState, blockWhenDisconnected: boolean) {
const actions = this.reduxActions.connection;
switch (tunnelState.state) {
case 'connecting':
@@ -604,10 +604,7 @@ export default class AppRenderer {
this.reduxActions.account.updateAccountExpiry(expiry);
}
- private detectStaleAccountExpiry(
- tunnelState: TunnelStateTransition,
- accountExpiry: AccountExpiry,
- ) {
+ private detectStaleAccountExpiry(tunnelState: TunnelState, accountExpiry: AccountExpiry) {
// It's likely that the account expiry is stale if the daemon managed to establish the tunnel.
if (tunnelState.state === 'connected' && accountExpiry.hasExpired()) {
log.info('Detected the stale account expiry.');
diff --git a/gui/src/renderer/components/NotificationArea.tsx b/gui/src/renderer/components/NotificationArea.tsx
index 062bb45da7..e120e25895 100644
--- a/gui/src/renderer/components/NotificationArea.tsx
+++ b/gui/src/renderer/components/NotificationArea.tsx
@@ -14,7 +14,7 @@ import {
NotificationTitle,
} from './NotificationBanner';
-import { BlockReason, TunnelStateTransition } from '../../shared/daemon-rpc-types';
+import { BlockReason, TunnelState } from '../../shared/daemon-rpc-types';
import AccountExpiry from '../lib/account-expiry';
import { parseAuthFailure } from '../lib/auth-failure';
import { IVersionReduxState } from '../redux/version/reducers';
@@ -22,7 +22,7 @@ import { IVersionReduxState } from '../redux/version/reducers';
interface IProps {
style?: Types.ViewStyleRuleSet;
accountExpiry?: AccountExpiry;
- tunnelState: TunnelStateTransition;
+ tunnelState: TunnelState;
version: IVersionReduxState;
openExternalLink: (url: string) => void;
blockWhenDisconnected: boolean;
diff --git a/gui/src/renderer/components/TunnelControl.tsx b/gui/src/renderer/components/TunnelControl.tsx
index ffb7ac2479..a03332194e 100644
--- a/gui/src/renderer/components/TunnelControl.tsx
+++ b/gui/src/renderer/components/TunnelControl.tsx
@@ -1,14 +1,14 @@
import * as React from 'react';
import { Component, Styles, Text, Types, View } from 'reactxp';
import { colors } from '../../config.json';
-import { TunnelStateTransition } from '../../shared/daemon-rpc-types';
+import { TunnelState } from '../../shared/daemon-rpc-types';
import { cities, countries, messages, relayLocations } from '../../shared/gettext';
import ConnectionPanelContainer from '../containers/ConnectionPanelContainer';
import * as AppButton from './AppButton';
import SecuredLabel, { SecuredDisplayStyle } from './SecuredLabel';
interface ITunnelControlProps {
- tunnelState: TunnelStateTransition;
+ tunnelState: TunnelState;
selectedRelayName: string;
city?: string;
country?: string;
diff --git a/gui/src/renderer/containers/ConnectionPanelContainer.tsx b/gui/src/renderer/containers/ConnectionPanelContainer.tsx
index 77b164c65b..44d3330c78 100644
--- a/gui/src/renderer/containers/ConnectionPanelContainer.tsx
+++ b/gui/src/renderer/containers/ConnectionPanelContainer.tsx
@@ -43,12 +43,12 @@ const mapStateToProps = (state: IReduxState) => {
const inAddress: IInAddress | undefined =
(status.state === 'connecting' || status.state === 'connected') && status.details
- ? tunnelEndpointToRelayInAddress(status.details)
+ ? tunnelEndpointToRelayInAddress(status.details.endpoint)
: undefined;
const bridgeInfo: IBridgeData | undefined =
(status.state === 'connecting' || status.state === 'connected') && status.details
- ? tunnelEndpointToBridgeData(status.details)
+ ? tunnelEndpointToBridgeData(status.details.endpoint)
: undefined;
return {
diff --git a/gui/src/renderer/redux/connection/actions.ts b/gui/src/renderer/redux/connection/actions.ts
index b84e85f8e6..8f5b2e62bb 100644
--- a/gui/src/renderer/redux/connection/actions.ts
+++ b/gui/src/renderer/redux/connection/actions.ts
@@ -2,17 +2,17 @@ import {
AfterDisconnect,
BlockReason,
ILocation,
- ITunnelEndpoint,
+ ITunnelStateRelayInfo,
} from '../../../shared/daemon-rpc-types';
interface IConnectingAction {
type: 'CONNECTING';
- tunnelEndpoint?: ITunnelEndpoint;
+ details?: ITunnelStateRelayInfo;
}
interface IConnectedAction {
type: 'CONNECTED';
- tunnelEndpoint: ITunnelEndpoint;
+ details: ITunnelStateRelayInfo;
}
interface IDisconnectedAction {
@@ -48,17 +48,17 @@ export type ConnectionAction =
| IBlockedAction
| IUpdateBlockStateAction;
-function connecting(tunnelEndpoint?: ITunnelEndpoint): IConnectingAction {
+function connecting(details?: ITunnelStateRelayInfo): IConnectingAction {
return {
type: 'CONNECTING',
- tunnelEndpoint,
+ details,
};
}
-function connected(tunnelEndpoint: ITunnelEndpoint): IConnectedAction {
+function connected(details: ITunnelStateRelayInfo): IConnectedAction {
return {
type: 'CONNECTED',
- tunnelEndpoint,
+ details,
};
}
diff --git a/gui/src/renderer/redux/connection/reducers.ts b/gui/src/renderer/redux/connection/reducers.ts
index 2719f3d3db..4772df8fc5 100644
--- a/gui/src/renderer/redux/connection/reducers.ts
+++ b/gui/src/renderer/redux/connection/reducers.ts
@@ -1,8 +1,8 @@
-import { Ip, TunnelStateTransition } from '../../../shared/daemon-rpc-types';
+import { Ip, TunnelState } from '../../../shared/daemon-rpc-types';
import { ReduxAction } from '../store';
export interface IConnectionReduxState {
- status: TunnelStateTransition;
+ status: TunnelState;
isBlocked: boolean;
ipv4?: Ip;
ipv6?: Ip;
@@ -41,13 +41,13 @@ export default function(
case 'CONNECTING':
return {
...state,
- status: { state: 'connecting', details: action.tunnelEndpoint },
+ status: { state: 'connecting', details: action.details },
};
case 'CONNECTED':
return {
...state,
- status: { state: 'connected', details: action.tunnelEndpoint },
+ status: { state: 'connected', details: action.details },
};
case 'DISCONNECTED':
diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts
index 120ef3a0b0..ec52d0ad5f 100644
--- a/gui/src/shared/daemon-rpc-types.ts
+++ b/gui/src/shared/daemon-rpc-types.ts
@@ -30,8 +30,6 @@ export type BlockReason =
export type AfterDisconnect = 'nothing' | 'block' | 'reconnect';
-export type TunnelState = 'connecting' | 'connected' | 'disconnecting' | 'disconnected' | 'blocked';
-
export type TunnelType = 'wireguard' | 'openvpn';
export function tunnelTypeToString(tunnel: TunnelType): string {
switch (tunnel) {
@@ -72,15 +70,20 @@ export interface IProxyEndpoint {
}
export type DaemonEvent =
- | { stateTransition: TunnelStateTransition }
+ | { tunnelState: TunnelState }
| { settings: ISettings }
| { relayList: IRelayList }
| { wireguardKey: KeygenEvent };
-export type TunnelStateTransition =
+export interface ITunnelStateRelayInfo {
+ endpoint: ITunnelEndpoint;
+ location: ILocation;
+}
+
+export type TunnelState =
| { state: 'disconnected' }
- | { state: 'connecting'; details?: ITunnelEndpoint }
- | { state: 'connected'; details: ITunnelEndpoint }
+ | { state: 'connecting'; details?: ITunnelStateRelayInfo }
+ | { state: 'connected'; details: ITunnelStateRelayInfo }
| { state: 'disconnecting'; details: AfterDisconnect }
| { state: 'blocked'; details: BlockReason };
diff --git a/gui/src/shared/ipc-event-channel.ts b/gui/src/shared/ipc-event-channel.ts
index b6292b554a..207e509779 100644
--- a/gui/src/shared/ipc-event-channel.ts
+++ b/gui/src/shared/ipc-event-channel.ts
@@ -13,7 +13,7 @@ import {
IRelayList,
ISettings,
RelaySettingsUpdate,
- TunnelStateTransition,
+ TunnelState,
} from './daemon-rpc-types';
export interface IAppStateSnapshot {
@@ -21,7 +21,7 @@ export interface IAppStateSnapshot {
isConnected: boolean;
autoStart: boolean;
accountHistory: AccountToken[];
- tunnelState: TunnelStateTransition;
+ tunnelState: TunnelState;
settings: ISettings;
location?: ILocation;
relays: IRelayList;
@@ -42,12 +42,12 @@ interface IReceiver<T> {
listen(fn: (value: T) => void): void;
}
-interface ITunnelMethods extends IReceiver<TunnelStateTransition> {
+interface ITunnelMethods extends IReceiver<TunnelState> {
connect(): Promise<void>;
disconnect(): Promise<void>;
}
-interface ITunnelHandlers extends ISender<TunnelStateTransition> {
+interface ITunnelHandlers extends ISender<TunnelState> {
handleConnect(fn: () => Promise<void>): void;
handleDisconnect(fn: () => Promise<void>): void;
}
diff --git a/gui/test/components/NotificationArea.spec.tsx b/gui/test/components/NotificationArea.spec.tsx
index 7b1a69bd8a..f2674e848c 100644
--- a/gui/test/components/NotificationArea.spec.tsx
+++ b/gui/test/components/NotificationArea.spec.tsx
@@ -63,9 +63,17 @@ describe('components/NotificationArea', () => {
tunnelState={{
state: 'connected',
details: {
- address: '1.2.3.4',
- protocol: 'tcp',
- tunnelType: 'openvpn',
+ endpoint: {
+ address: '1.2.3.4',
+ protocol: 'tcp',
+ tunnelType: 'openvpn',
+ },
+ location: {
+ country: 'Sweden',
+ latitude: 57.70887,
+ longitude: 11.97456,
+ mullvadExitIp: true,
+ },
},
}}
version={defaultVersion}
diff --git a/mullvad-cli/src/cmds/status.rs b/mullvad-cli/src/cmds/status.rs
index 4846296fbb..12ad4d65be 100644
--- a/mullvad-cli/src/cmds/status.rs
+++ b/mullvad-cli/src/cmds/status.rs
@@ -1,8 +1,8 @@
use crate::{new_rpc_client, Command, Error, Result};
use futures::{Future, Stream};
use mullvad_ipc_client::DaemonRpcClient;
-use mullvad_types::{auth_failed::AuthFailed, DaemonEvent};
-use talpid_types::tunnel::{BlockReason, TunnelStateTransition};
+use mullvad_types::{auth_failed::AuthFailed, states::TunnelState, DaemonEvent};
+use talpid_types::tunnel::BlockReason;
pub struct Status;
@@ -39,11 +39,11 @@ impl Command for Status {
.map_err(Error::CantSubscribe)?;
for event in subscription.wait() {
match event? {
- DaemonEvent::StateTransition(new_state) => {
+ DaemonEvent::TunnelState(new_state) => {
print_state(&new_state);
- use self::TunnelStateTransition::*;
+ use self::TunnelState::*;
match new_state {
- Connected(_) | Disconnected => print_location(&mut rpc)?,
+ Connected { .. } | Disconnected => print_location(&mut rpc)?,
_ => {}
}
}
@@ -69,15 +69,15 @@ impl Command for Status {
}
}
-fn print_state(state: &TunnelStateTransition) {
- use self::TunnelStateTransition::*;
+fn print_state(state: &TunnelState) {
+ use self::TunnelState::*;
print!("Tunnel status: ");
match state {
Blocked(reason) => print_blocked_reason(reason),
- Connected(details) => {
- println!("Connected to {}", details);
+ Connected { endpoint, .. } => {
+ println!("Connected to {}", endpoint);
}
- Connecting(details) => println!("Connecting to {}...", details),
+ Connecting { endpoint, .. } => println!("Connecting to {}...", endpoint),
Disconnected => println!("Disconnected"),
Disconnecting(_) => println!("Disconnecting..."),
}
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index 7a559624ec..0e66149915 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -41,7 +41,7 @@ use mullvad_types::{
RelayConstraintsUpdate, RelaySettings, RelaySettingsUpdate, TunnelConstraints,
},
relay_list::{Relay, RelayList},
- states::TargetState,
+ states::{TargetState, TunnelState},
version::{AppVersion, AppVersionInfo},
wireguard::KeygenEvent,
};
@@ -146,13 +146,13 @@ enum DaemonExecutionState {
}
impl DaemonExecutionState {
- pub fn shutdown(&mut self, tunnel_state: &TunnelStateTransition) {
+ pub fn shutdown(&mut self, tunnel_state: &TunnelState) {
use self::DaemonExecutionState::*;
match self {
Running => {
match tunnel_state {
- TunnelStateTransition::Disconnected => mem::replace(self, Finished),
+ TunnelState::Disconnected => mem::replace(self, Finished),
_ => mem::replace(self, Exiting),
};
}
@@ -196,7 +196,7 @@ impl DaemonCommandSender {
/// Trait representing something that can broadcast daemon events.
pub trait EventListener {
/// Notify that the tunnel state changed.
- fn notify_new_state(&self, new_state: TunnelStateTransition);
+ fn notify_new_state(&self, new_state: TunnelState);
/// Notify that the settings changed.
fn notify_settings(&self, settings: Settings);
@@ -210,7 +210,7 @@ pub trait EventListener {
pub struct Daemon<L: EventListener = ManagementInterfaceEventBroadcaster> {
tunnel_command_tx: SyncUnboundedSender<TunnelCommand>,
- tunnel_state: TunnelStateTransition,
+ tunnel_state: TunnelState,
target_state: TargetState,
state: DaemonExecutionState,
rx: mpsc::Receiver<InternalDaemonEvent>,
@@ -388,7 +388,7 @@ where
let mut daemon = Daemon {
tunnel_command_tx: Sink::wait(tunnel_command_tx),
- tunnel_state: TunnelStateTransition::Disconnected,
+ tunnel_state: TunnelState::Disconnected,
target_state: TargetState::Unsecured,
state: DaemonExecutionState::Running,
rx: internal_event_rx,
@@ -453,15 +453,33 @@ where
Ok(())
}
- fn handle_tunnel_state_transition(&mut self, tunnel_state: TunnelStateTransition) {
- use self::TunnelStateTransition::*;
+ fn handle_tunnel_state_transition(&mut self, tunnel_state_transition: TunnelStateTransition) {
+ let tunnel_state = match tunnel_state_transition {
+ TunnelStateTransition::Disconnected => TunnelState::Disconnected,
+ TunnelStateTransition::Connecting(endpoint) => TunnelState::Connecting {
+ endpoint,
+ location: self
+ .build_location_from_relay()
+ .expect("No relay to get location from"),
+ },
+ TunnelStateTransition::Connected(endpoint) => TunnelState::Connected {
+ endpoint,
+ location: self
+ .build_location_from_relay()
+ .expect("No relay to get location from"),
+ },
+ TunnelStateTransition::Disconnecting(after_disconnect) => {
+ TunnelState::Disconnecting(after_disconnect)
+ }
+ TunnelStateTransition::Blocked(reason) => TunnelState::Blocked(reason.clone()),
+ };
self.unschedule_reconnect();
debug!("New tunnel state: {:?}", tunnel_state);
match tunnel_state {
- Disconnected => self.state.disconnected(),
- Blocked(ref reason) => {
+ TunnelState::Disconnected => self.state.disconnected(),
+ TunnelState::Blocked(ref reason) => {
info!("Blocking all network connections, reason: {}", reason);
if let BlockReason::AuthFailed(_) = reason {
@@ -766,33 +784,33 @@ where
Self::oneshot_send(tx, Ok(()), "target state");
}
- fn on_get_state(&self, tx: oneshot::Sender<TunnelStateTransition>) {
+ fn on_get_state(&self, tx: oneshot::Sender<TunnelState>) {
Self::oneshot_send(tx, self.tunnel_state.clone(), "current state");
}
fn on_get_current_location(&self, tx: oneshot::Sender<Option<GeoIpLocation>>) {
- use self::TunnelStateTransition::*;
+ use self::TunnelState::*;
let get_location: Box<dyn Future<Item = Option<GeoIpLocation>, Error = ()> + Send> =
- match self.tunnel_state {
+ match &self.tunnel_state {
Disconnected => Box::new(self.get_geo_location().map(Some)),
- Connecting(_) | Disconnecting(..) => match self.build_location_from_relay() {
+ Connecting { location, .. } => Box::new(future::result(Ok(Some(location.clone())))),
+ Disconnecting(..) => match self.build_location_from_relay() {
Some(relay_location) => Box::new(future::result(Ok(Some(relay_location)))),
// Custom relay is set, no location is known
None => Box::new(future::result(Ok(None))),
},
- Connected(_) => match self.build_location_from_relay() {
- Some(location_from_relay) => Box::new(
+ Connected { location, .. } => {
+ let relay_location = location.clone();
+ Box::new(
self.get_geo_location()
.map(|fetched_location| GeoIpLocation {
ipv4: fetched_location.ipv4,
ipv6: fetched_location.ipv6,
- ..location_from_relay
+ ..relay_location
})
.map(Some),
- ),
- // Custom relay is set, no location is known intrinsicly
- None => Box::new(self.get_geo_location().map(Some)),
- },
+ )
+ }
Blocked(..) => {
// We are not online at all at this stage so no location data is available.
Box::new(future::result(Ok(None)))
diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs
index 0ef34090d7..103e39b25e 100644
--- a/mullvad-daemon/src/management_interface.rs
+++ b/mullvad-daemon/src/management_interface.rs
@@ -18,7 +18,7 @@ use mullvad_types::{
relay_constraints::{BridgeSettings, BridgeState, RelaySettingsUpdate},
relay_list::RelayList,
settings::{self, Settings},
- states::TargetState,
+ states::{TargetState, TunnelState},
version, DaemonEvent,
};
use std::{
@@ -27,7 +27,7 @@ use std::{
};
use talpid_core::mpsc::IntoSender;
use talpid_ipc;
-use talpid_types::{net::wireguard, tunnel::TunnelStateTransition, ErrorExt};
+use talpid_types::{net::wireguard, ErrorExt};
use uuid;
/// FIXME(linus): This is here just because the futures crate has deprecated it and jsonrpc_core
@@ -87,7 +87,7 @@ build_rpc_trait! {
/// Returns the current state of the Mullvad client. Changes to this state will
/// be announced to subscribers of `new_state`.
#[rpc(meta, name = "get_state")]
- fn get_state(&self, Self::Metadata) -> BoxFuture<TunnelStateTransition, Error>;
+ fn get_state(&self, Self::Metadata) -> BoxFuture<TunnelState, Error>;
/// Performs a geoIP lookup and returns the current location as perceived by the public
/// internet.
@@ -172,7 +172,7 @@ pub enum ManagementCommand {
/// Change target state.
SetTargetState(OneshotSender<Result<(), ()>>, TargetState),
/// Request the current state.
- GetState(OneshotSender<TunnelStateTransition>),
+ GetState(OneshotSender<TunnelState>),
/// Get the current geographical location.
GetCurrentLocation(OneshotSender<Option<GeoIpLocation>>),
/// Request the metadata for an account.
@@ -280,9 +280,9 @@ pub struct ManagementInterfaceEventBroadcaster {
impl EventListener for ManagementInterfaceEventBroadcaster {
/// Sends a new state update to all `new_state` subscribers of the management interface.
- fn notify_new_state(&self, new_state: TunnelStateTransition) {
+ fn notify_new_state(&self, new_state: TunnelState) {
log::debug!("Broadcasting new state: {:?}", new_state);
- self.notify(DaemonEvent::StateTransition(new_state));
+ self.notify(DaemonEvent::TunnelState(new_state));
}
/// Sends settings to all `settings` subscribers of the management interface.
@@ -492,7 +492,7 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn get_state(&self, _: Self::Metadata) -> BoxFuture<TunnelStateTransition, Error> {
+ fn get_state(&self, _: Self::Metadata) -> BoxFuture<TunnelState, Error> {
log::debug!("get_state");
let (state_tx, state_rx) = sync::oneshot::channel();
let future = self
diff --git a/mullvad-ipc-client/src/lib.rs b/mullvad-ipc-client/src/lib.rs
index d42f165026..98b6206ba4 100644
--- a/mullvad-ipc-client/src/lib.rs
+++ b/mullvad-ipc-client/src/lib.rs
@@ -9,12 +9,13 @@ use mullvad_types::{
relay_constraints::{BridgeSettings, BridgeState, RelaySettings, RelaySettingsUpdate},
relay_list::RelayList,
settings::{Settings, TunnelOptions},
+ states::TunnelState,
version::AppVersionInfo,
DaemonEvent,
};
use serde::{Deserialize, Serialize};
use std::{io, path::Path, thread};
-use talpid_types::{net::wireguard, tunnel::TunnelStateTransition};
+use talpid_types::net::wireguard;
static NO_ARGS: [u8; 0] = [];
@@ -147,7 +148,7 @@ impl DaemonRpcClient {
self.call("get_relay_settings", &NO_ARGS)
}
- pub fn get_state(&mut self) -> Result<TunnelStateTransition> {
+ pub fn get_state(&mut self) -> Result<TunnelState> {
self.call("get_state", &NO_ARGS)
}
diff --git a/mullvad-jni/src/daemon_interface.rs b/mullvad-jni/src/daemon_interface.rs
index a99c6e7cac..661550ca17 100644
--- a/mullvad-jni/src/daemon_interface.rs
+++ b/mullvad-jni/src/daemon_interface.rs
@@ -1,11 +1,16 @@
use futures::{sync::oneshot, Future};
use mullvad_daemon::{DaemonCommandSender, ManagementCommand};
use mullvad_types::{
- account::AccountData, location::GeoIpLocation, relay_constraints::RelaySettingsUpdate,
- relay_list::RelayList, settings::Settings, states::TargetState, wireguard::KeygenEvent,
+ account::AccountData,
+ location::GeoIpLocation,
+ relay_constraints::RelaySettingsUpdate,
+ relay_list::RelayList,
+ settings::Settings,
+ states::{TargetState, TunnelState},
+ wireguard::KeygenEvent,
};
use parking_lot::Mutex;
-use talpid_types::{net::wireguard, tunnel::TunnelStateTransition};
+use talpid_types::net::wireguard;
#[derive(Debug, err_derive::Error)]
pub enum Error {
@@ -107,7 +112,7 @@ impl DaemonInterface {
Ok(rx.wait().map_err(|_| Error::NoResponse)?)
}
- pub fn get_state(&self) -> Result<TunnelStateTransition> {
+ pub fn get_state(&self) -> Result<TunnelState> {
let (tx, rx) = oneshot::channel();
self.send_command(ManagementCommand::GetState(tx))?;
diff --git a/mullvad-jni/src/into_java.rs b/mullvad-jni/src/into_java.rs
index c5fd9667c0..204f023ec0 100644
--- a/mullvad-jni/src/into_java.rs
+++ b/mullvad-jni/src/into_java.rs
@@ -12,11 +12,12 @@ use mullvad_types::{
relay_constraints::{Constraint, LocationConstraint, RelayConstraints, RelaySettings},
relay_list::{Relay, RelayList, RelayListCity, RelayListCountry},
settings::Settings,
+ states::TunnelState,
CustomTunnelEndpoint,
};
use std::{fmt::Debug, net::IpAddr};
use talpid_core::tunnel::tun_provider::TunConfig;
-use talpid_types::{net::wireguard::PublicKey, tunnel::TunnelStateTransition};
+use talpid_types::net::wireguard::PublicKey;
pub trait IntoJava<'env> {
type JavaType;
@@ -460,24 +461,24 @@ impl<'env> IntoJava<'env> for Settings {
}
}
-impl<'env> IntoJava<'env> for TunnelStateTransition {
+impl<'env> IntoJava<'env> for TunnelState {
type JavaType = JObject<'env>;
fn into_java(self, env: &JNIEnv<'env>) -> Self::JavaType {
let variant = match self {
- TunnelStateTransition::Disconnected => "Disconnected",
- TunnelStateTransition::Connecting(_) => "Connecting",
- TunnelStateTransition::Connected(_) => "Connected",
- TunnelStateTransition::Disconnecting(_) => "Disconnecting",
- TunnelStateTransition::Blocked(_) => "Blocked",
+ TunnelState::Disconnected => "Disconnected",
+ TunnelState::Connecting { .. } => "Connecting",
+ TunnelState::Connected { .. } => "Connected",
+ TunnelState::Disconnecting(_) => "Disconnecting",
+ TunnelState::Blocked(_) => "Blocked",
};
let class = get_class(&format!(
- "net/mullvad/mullvadvpn/model/TunnelStateTransition${}",
+ "net/mullvad/mullvadvpn/model/TunnelState${}",
variant
));
env.new_object(&class, "()V", &[])
- .expect("Failed to create TunnelStateTransition sub-class variant Java object")
+ .expect("Failed to create TunnelState sub-class variant Java object")
}
}
diff --git a/mullvad-jni/src/jni_event_listener.rs b/mullvad-jni/src/jni_event_listener.rs
index 37f19ad944..8fa2456d5b 100644
--- a/mullvad-jni/src/jni_event_listener.rs
+++ b/mullvad-jni/src/jni_event_listener.rs
@@ -5,9 +5,11 @@ use jni::{
AttachGuard, JNIEnv,
};
use mullvad_daemon::EventListener;
-use mullvad_types::{relay_list::RelayList, settings::Settings, wireguard::KeygenEvent};
+use mullvad_types::{
+ relay_list::RelayList, settings::Settings, states::TunnelState, wireguard::KeygenEvent,
+};
use std::{sync::mpsc, thread};
-use talpid_types::{tunnel::TunnelStateTransition, ErrorExt};
+use talpid_types::ErrorExt;
#[derive(Debug, err_derive::Error)]
pub enum Error {
@@ -24,7 +26,7 @@ pub enum Error {
enum Event {
RelayList(RelayList),
Settings(Settings),
- Tunnel(TunnelStateTransition),
+ Tunnel(TunnelState),
}
#[derive(Clone, Debug)]
@@ -37,7 +39,7 @@ impl JniEventListener {
}
impl EventListener for JniEventListener {
- fn notify_new_state(&self, state: TunnelStateTransition) {
+ fn notify_new_state(&self, state: TunnelState) {
let _ = self.0.send(Event::Tunnel(state));
}
@@ -115,7 +117,7 @@ impl<'env> JniEventHandler<'env> {
&env,
&class,
"notifyTunnelStateEvent",
- "(Lnet/mullvad/mullvadvpn/model/TunnelStateTransition;)V",
+ "(Lnet/mullvad/mullvadvpn/model/TunnelState;)V",
)?;
Ok(JniEventHandler {
@@ -184,14 +186,14 @@ impl<'env> JniEventHandler<'env> {
}
}
- fn handle_tunnel_event(&self, event: TunnelStateTransition) {
- let java_tunnel_state_transition = self.env.auto_local(event.into_java(&self.env));
+ fn handle_tunnel_event(&self, event: TunnelState) {
+ let java_tunnel_state = self.env.auto_local(event.into_java(&self.env));
let result = self.env.call_method_unchecked(
self.mullvad_ipc_client,
self.notify_tunnel_event,
JavaType::Primitive(Primitive::Void),
- &[JValue::Object(java_tunnel_state_transition.as_obj())],
+ &[JValue::Object(java_tunnel_state.as_obj())],
);
if let Err(error) = result {
diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs
index ff587a4b38..2ec4cac08a 100644
--- a/mullvad-jni/src/lib.rs
+++ b/mullvad-jni/src/lib.rs
@@ -53,11 +53,11 @@ const CLASSES_TO_LOAD: &[&str] = &[
"net/mullvad/mullvadvpn/model/RelaySettingsUpdate$RelayConstraintsUpdate",
"net/mullvad/mullvadvpn/model/Settings",
"net/mullvad/mullvadvpn/model/TunConfig",
- "net/mullvad/mullvadvpn/model/TunnelStateTransition$Blocked",
- "net/mullvad/mullvadvpn/model/TunnelStateTransition$Connected",
- "net/mullvad/mullvadvpn/model/TunnelStateTransition$Connecting",
- "net/mullvad/mullvadvpn/model/TunnelStateTransition$Disconnected",
- "net/mullvad/mullvadvpn/model/TunnelStateTransition$Disconnecting",
+ "net/mullvad/mullvadvpn/model/TunnelState$Blocked",
+ "net/mullvad/mullvadvpn/model/TunnelState$Connected",
+ "net/mullvad/mullvadvpn/model/TunnelState$Connecting",
+ "net/mullvad/mullvadvpn/model/TunnelState$Disconnected",
+ "net/mullvad/mullvadvpn/model/TunnelState$Disconnecting",
"net/mullvad/mullvadvpn/MullvadDaemon",
"net/mullvad/mullvadvpn/MullvadVpnService",
];
diff --git a/mullvad-types/src/lib.rs b/mullvad-types/src/lib.rs
index 75088341d3..448befd16f 100644
--- a/mullvad-types/src/lib.rs
+++ b/mullvad-types/src/lib.rs
@@ -27,7 +27,7 @@ pub use crate::custom_tunnel::*;
#[serde(rename_all = "snake_case")]
pub enum DaemonEvent {
/// The daemon transitioned into a new state.
- StateTransition(talpid_types::tunnel::TunnelStateTransition),
+ TunnelState(states::TunnelState),
/// The daemon settings changed.
Settings(settings::Settings),
diff --git a/mullvad-types/src/location.rs b/mullvad-types/src/location.rs
index 629f15d37a..fbb2c1a7ef 100644
--- a/mullvad-types/src/location.rs
+++ b/mullvad-types/src/location.rs
@@ -63,7 +63,7 @@ pub struct AmIMullvad {
}
/// GeoIP information exposed from the daemon to frontends.
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GeoIpLocation {
pub ipv4: Option<Ipv4Addr>,
pub ipv6: Option<Ipv6Addr>,
diff --git a/mullvad-types/src/states.rs b/mullvad-types/src/states.rs
index a5bb8a8b59..91618025ac 100644
--- a/mullvad-types/src/states.rs
+++ b/mullvad-types/src/states.rs
@@ -1,4 +1,9 @@
+use crate::location::GeoIpLocation;
use serde::{Deserialize, Serialize};
+use talpid_types::{
+ net::TunnelEndpoint,
+ tunnel::{ActionAfterDisconnect, BlockReason},
+};
/// Represents the state the client strives towards.
/// When in `Secured`, the client should keep the computer from leaking and try to
@@ -9,3 +14,31 @@ pub enum TargetState {
Unsecured,
Secured,
}
+
+/// Represents the state the client tunnel is in.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+#[serde(tag = "state", content = "details")]
+pub enum TunnelState {
+ Disconnected,
+ Connecting {
+ endpoint: TunnelEndpoint,
+ location: GeoIpLocation,
+ },
+ Connected {
+ endpoint: TunnelEndpoint,
+ location: GeoIpLocation,
+ },
+ Disconnecting(ActionAfterDisconnect),
+ Blocked(BlockReason),
+}
+
+impl TunnelState {
+ /// Returns true if the tunnel state is the blocked state.
+ pub fn is_blocked(&self) -> bool {
+ match self {
+ TunnelState::Blocked(_) => true,
+ _ => false,
+ }
+ }
+}