diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-07-01 08:34:09 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-07-01 08:34:09 -0300 |
| commit | 6d6d74df30a031ce8a8db2602485917ac6ca66da (patch) | |
| tree | 145b7c8083be620ff8c7274b613e14caf58aeb14 | |
| parent | 8f6c45227f4d9af8bf2dd9a39a7adb86d4fa8be6 (diff) | |
| parent | 2185ba222098cca1f802c6d3e3acb9a4a3f49f2d (diff) | |
| download | mullvadvpn-6d6d74df30a031ce8a8db2602485917ac6ca66da.tar.xz mullvadvpn-6d6d74df30a031ce8a8db2602485917ac6ca66da.zip | |
Merge branch 'broadcast-relay-location'
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, + } + } +} |
