diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2017-06-16 15:29:15 +0200 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2017-06-16 15:29:15 +0200 |
| commit | 29de1387c9cdcd2a06bbb6ee1c4c9f36734f6107 (patch) | |
| tree | 11f80ee610fb2e3ee73a8361ef5d03491bdb8830 /mullvad_daemon/src | |
| parent | c2aaa4eb26af015ef949785668751cded783675d (diff) | |
| parent | 44346a5d28264ef15915336096a4e0d622d662ec (diff) | |
| download | mullvadvpn-29de1387c9cdcd2a06bbb6ee1c4c9f36734f6107.tar.xz mullvadvpn-29de1387c9cdcd2a06bbb6ee1c4c9f36734f6107.zip | |
Merge branch 'master-new-daemon'
Diffstat (limited to 'mullvad_daemon/src')
| -rw-r--r-- | mullvad_daemon/src/ipc_api.rs | 90 | ||||
| -rw-r--r-- | mullvad_daemon/src/main.rs | 325 | ||||
| -rw-r--r-- | mullvad_daemon/src/management_interface.rs | 301 | ||||
| -rw-r--r-- | mullvad_daemon/src/states.rs | 21 |
4 files changed, 631 insertions, 106 deletions
diff --git a/mullvad_daemon/src/ipc_api.rs b/mullvad_daemon/src/ipc_api.rs deleted file mode 100644 index 84932a0b8f..0000000000 --- a/mullvad_daemon/src/ipc_api.rs +++ /dev/null @@ -1,90 +0,0 @@ -use jsonrpc_core::Error; -use jsonrpc_core::futures::BoxFuture; -use jsonrpc_macros::pubsub; -use jsonrpc_pubsub::SubscriptionId; - -use std::collections::HashMap; -use std::net::IpAddr; - -pub type AccountToken = String; -pub type CountryCode = String; - -build_rpc_trait! { - pub trait IpcApi { - type Metadata; - - /// Fetches and returns metadata about an account. Returns an error on non-existing - /// accounts. - #[rpc(name = "get_account_data")] - fn get_account_data(&self, AccountToken) -> Result<AccountData, Error>; - - /// Returns available countries. - #[rpc(name = "get_countries")] - fn get_countries(&self) -> Result<HashMap<CountryCode, String>, Error>; - - /// Set which account to connect with - #[rpc(name = "set_account")] - fn set_account(&self, AccountToken) -> Result<(), Error>; - - /// Set which country to connect to - #[rpc(name = "set_country")] - fn set_country(&self, CountryCode) -> Result<(), Error>; - - /// Set if the backend should automatically establish a tunnel on start or not. - #[rpc(name = "set_autoconnect")] - fn set_autoconnect(&self, bool) -> Result<(), Error>; - - /// Try to connect if disconnected, or do nothing if already connecting/connected. - #[rpc(name = "connect")] - fn connect(&self) -> Result<(), Error>; - - /// Disconnect the VPN tunnel if it is connecting/connected. Does nothing if already - /// disconnected. - #[rpc(name = "disconnect")] - fn disconnect(&self) -> Result<(), Error>; - - /// Returns the current security state of the Mullvad client. Changes to this state will - /// be announced to subscribers of `event`. - #[rpc(name = "get_state")] - fn get_state(&self) -> Result<SecurityState, Error>; - - /// Returns the current public IP of this computer. - #[rpc(name = "get_ip")] - fn get_ip(&self) -> Result<IpAddr, Error>; - - /// Performs a geoIP lookup and returns the current location as perceived by the public - /// internet. - #[rpc(name = "get_location")] - fn get_location(&self) -> Result<Location, Error>; - - #[pubsub(name = "event")] { - /// Subscribes to the `event` notifications. - #[rpc(name = "event_subscribe")] - fn subscribe(&self, Self::Metadata, pubsub::Subscriber<String>); - - /// Unsubscribes from the `event` notifications. - #[rpc(name = "event_unsubscribe")] - fn unsubscribe(&self, SubscriptionId) -> BoxFuture<bool, Error>; - } - } -} - -#[derive(Serialize)] -pub struct AccountData { - pub paid_until: String, -} - -#[derive(Serialize)] -pub struct Location { - pub latlong: [f64; 2], - pub country: String, - pub city: String, -} - -#[derive(Serialize)] -pub enum SecurityState { - Unsecured, - Securing, - Secured, - Unsecuring, -} diff --git a/mullvad_daemon/src/main.rs b/mullvad_daemon/src/main.rs index 95033b1564..fa1db7765c 100644 --- a/mullvad_daemon/src/main.rs +++ b/mullvad_daemon/src/main.rs @@ -8,37 +8,330 @@ extern crate serde; #[macro_use] extern crate serde_derive; -extern crate talpid_ipc; - extern crate jsonrpc_core; extern crate jsonrpc_pubsub; #[macro_use] extern crate jsonrpc_macros; extern crate jsonrpc_ws_server; +extern crate uuid; +#[macro_use] +extern crate lazy_static; + +extern crate talpid_core; +extern crate talpid_ipc; + +mod management_interface; +mod states; + +use management_interface::{ManagementInterfaceServer, TunnelCommand}; +use states::{SecurityState, TargetState}; + +use std::sync::{Arc, Mutex, mpsc}; +use std::thread; + +use talpid_core::net::RemoteAddr; +use talpid_core::tunnel::{self, TunnelEvent, TunnelMonitor}; + +error_chain!{ + errors { + /// The client is in the wrong state for the requested operation. Optimally the code should + /// be written in such a way so such states can't exist. + InvalidState { + description("Client is in an invalid state for the requested operation") + } + TunnelError(msg: &'static str) { + description("Error in the tunnel monitor") + display("Tunnel monitor error: {}", msg) + } + ManagementInterfaceError(msg: &'static str) { + description("Error in the management interface") + display("Management interface error: {}", msg) + } + } +} + +lazy_static! { + // Temporary store of hardcoded remotes. + static ref REMOTES: [RemoteAddr; 3] = [ + RemoteAddr::new("se5.mullvad.net", 1300), + RemoteAddr::new("se6.mullvad.net", 1300), + RemoteAddr::new("se7.mullvad.net", 1300), + ]; +} + +pub enum DaemonEvent { + TunnelEvent(TunnelEvent), + TunnelExit(tunnel::Result<()>), + ManagementInterfaceEvent(TunnelCommand), + ManagementInterfaceExit(talpid_ipc::Result<()>), +} + +impl From<TunnelEvent> for DaemonEvent { + fn from(tunnel_event: TunnelEvent) -> Self { + DaemonEvent::TunnelEvent(tunnel_event) + } +} + +impl From<TunnelCommand> for DaemonEvent { + fn from(tunnel_command: TunnelCommand) -> Self { + DaemonEvent::ManagementInterfaceEvent(tunnel_command) + } +} + +/// Represents the internal state of the actual tunnel. +// TODO(linus): Put the tunnel::CloseHandle into this state, so it can't exist when not running. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum TunnelState { + /// No tunnel is running. + NotRunning, + /// The tunnel has been started, but it is not established/functional. + Down, + /// The tunnel is up and working. + Up, +} + +impl TunnelState { + pub fn as_security_state(&self) -> SecurityState { + match *self { + TunnelState::Up => SecurityState::Secured, + _ => SecurityState::Unsecured, + } + } +} + + +struct Daemon { + state: TunnelState, + last_broadcasted_state: SecurityState, + target_state: TargetState, + rx: mpsc::Receiver<DaemonEvent>, + tx: mpsc::Sender<DaemonEvent>, + tunnel_close_handle: Option<tunnel::CloseHandle>, + management_interface_broadcaster: management_interface::EventBroadcaster, + + // Just for testing. A cyclic iterator iterating over the hardcoded remotes, + // picking a new one for each retry. + remote_iter: std::iter::Cycle<std::iter::Cloned<std::slice::Iter<'static, RemoteAddr>>>, +} + +impl Daemon { + pub fn new() -> Result<Self> { + let (tx, rx) = mpsc::channel(); + let management_interface_broadcaster = Self::start_management_interface(tx.clone())?; + Ok( + Daemon { + state: TunnelState::NotRunning, + last_broadcasted_state: SecurityState::Unsecured, + target_state: TargetState::Unsecured, + rx, + tx, + tunnel_close_handle: None, + management_interface_broadcaster, + remote_iter: REMOTES.iter().cloned().cycle(), + }, + ) + } + + // Starts the management interface and spawns a thread that will process it. + // Returns a handle that allows notifying all subscribers on events. + fn start_management_interface(event_tx: mpsc::Sender<DaemonEvent>) + -> Result<management_interface::EventBroadcaster> { + let server = Self::start_management_interface_server(event_tx.clone())?; + let event_broadcaster = server.event_broadcaster(); + Self::spawn_management_interface_wait_thread(server, event_tx); + Ok(event_broadcaster) + } + + fn start_management_interface_server(event_tx: mpsc::Sender<DaemonEvent>) + -> Result<ManagementInterfaceServer> { + let server = + ManagementInterfaceServer::start(event_tx.clone()) + .chain_err(|| ErrorKind::ManagementInterfaceError("Failed to start server"),)?; + info!( + "Mullvad management interface listening on {}", + server.address() + ); + Ok(server) + } + + fn spawn_management_interface_wait_thread(server: ManagementInterfaceServer, + exit_tx: mpsc::Sender<DaemonEvent>) { + thread::spawn( + move || { + let result = server.wait(); + debug!("Mullvad management interface shut down"); + let _ = exit_tx.send(DaemonEvent::ManagementInterfaceExit(result)); + }, + ); + } + + /// Consume the `Daemon` and run the main event loop. Blocks until an error happens. + pub fn run(mut self) -> Result<()> { + while let Ok(event) = self.rx.recv() { + self.handle_event(event)?; + } + Ok(()) + } + + fn handle_event(&mut self, event: DaemonEvent) -> Result<()> { + use DaemonEvent::*; + match event { + TunnelEvent(event) => Ok(self.handle_tunnel_event(event)), + TunnelExit(result) => self.handle_tunnel_exit(result), + ManagementInterfaceEvent(event) => self.handle_management_interface_event(event), + ManagementInterfaceExit(result) => self.handle_management_interface_exit(result), + } + } + + fn handle_tunnel_event(&mut self, tunnel_event: TunnelEvent) { + info!("Tunnel event: {:?}", tunnel_event); + let new_state = match tunnel_event { + TunnelEvent::Up => TunnelState::Up, + TunnelEvent::Down => TunnelState::Down, + }; + self.set_state(new_state); + } + + fn handle_tunnel_exit(&mut self, result: tunnel::Result<()>) -> Result<()> { + self.tunnel_close_handle = None; + if let Err(e) = result { + log_error("Tunnel exited in an unexpected way", e); + } + self.set_state(TunnelState::NotRunning); + self.apply_target_state() + } + + fn handle_management_interface_event(&mut self, event: TunnelCommand) -> Result<()> { + match event { + TunnelCommand::SetTargetState(state) => self.set_target_state(state)?, + TunnelCommand::GetState(tx) => { + if let Err(_) = tx.send(self.last_broadcasted_state) { + warn!("Unable to send current state to management interface client",); + } + } + } + Ok(()) + } + + fn handle_management_interface_exit(&self, result: talpid_ipc::Result<()>) -> Result<()> { + let error = ErrorKind::ManagementInterfaceError("Server exited unexpectedly"); + match result { + Ok(()) => Err(error.into()), + e => e.chain_err(|| error), + } + } + + /// Update the state of the client. If it changed, notify the subscribers. + fn set_state(&mut self, new_state: TunnelState) { + if new_state != self.state { + self.state = new_state; + let new_security_state = self.state.as_security_state(); + if self.last_broadcasted_state != new_security_state { + self.last_broadcasted_state = new_security_state; + self.management_interface_broadcaster.notify_new_state(new_security_state); + } + } + } + + /// Set the target state of the client. If it changed trigger the operations needed to progress + /// towards that state. + fn set_target_state(&mut self, new_state: TargetState) -> Result<()> { + if new_state != self.target_state { + self.target_state = new_state; + self.apply_target_state() + } else { + Ok(()) + } + } -pub mod ipc_api; -pub mod mock_ipc; + fn apply_target_state(&mut self) -> Result<()> { + match (self.target_state, self.state) { + (TargetState::Secured, TunnelState::NotRunning) => { + debug!("Triggering tunnel start"); + self.start_tunnel() + } + (TargetState::Unsecured, TunnelState::Down) | + (TargetState::Unsecured, TunnelState::Up) => { + if let Some(close_handle) = self.tunnel_close_handle.take() { + debug!("Triggering tunnel stop"); + // This close operation will block until the tunnel is dead. + close_handle + .close() + .chain_err(|| ErrorKind::TunnelError("Unable to kill tunnel")) + } else { + Ok(()) + } + } + (target_state, state) => { + trace!( + "apply_target_state does nothing on TargetState::{:?} TunnelState::{:?}", + target_state, + state + ); + Ok(()) + } + } + } + + fn start_tunnel(&mut self) -> Result<()> { + ensure!( + self.state == TunnelState::NotRunning, + ErrorKind::InvalidState + ); + let remote = self.remote_iter.next().unwrap(); + let tunnel_monitor = self.spawn_tunnel_monitor(remote)?; + self.tunnel_close_handle = Some(tunnel_monitor.close_handle()); + self.spawn_tunnel_monitor_wait_thread(tunnel_monitor); + + self.set_state(TunnelState::Down); + Ok(()) + } + + fn spawn_tunnel_monitor(&self, remote: RemoteAddr) -> Result<TunnelMonitor> { + // Must wrap the channel in a Mutex because TunnelMonitor forces the closure to be Sync + let event_tx = Arc::new(Mutex::new(self.tx.clone())); + let on_tunnel_event = move |event| { + let _ = event_tx.lock().unwrap().send(DaemonEvent::TunnelEvent(event)); + }; + TunnelMonitor::new(remote, on_tunnel_event) + .chain_err(|| ErrorKind::TunnelError("Unable to start tunnel monitor")) + } + + fn spawn_tunnel_monitor_wait_thread(&self, tunnel_monitor: TunnelMonitor) { + let error_tx = self.tx.clone(); + thread::spawn( + move || { + let result = tunnel_monitor.wait(); + let _ = error_tx.send(DaemonEvent::TunnelExit(result)); + trace!("Tunnel monitor thread exit"); + }, + ); + } +} + + +fn log_error<E>(msg: &str, error: E) + where E: error_chain::ChainedError +{ + error!("{}: {}", msg, error); + for e in error.iter().skip(1) { + error!("Caused by {}", e); + } +} -error_chain!{} quick_main!(run); fn run() -> Result<()> { init_logger()?; - let server = start_ipc()?; - info!("Mullvad daemon listening on {}", server.address()); - main_loop(server) + let daemon = Daemon::new().chain_err(|| "Unable to initialize daemon")?; + daemon.run()?; + + debug!("Mullvad daemon is quitting"); + Ok(()) } fn init_logger() -> Result<()> { env_logger::init().chain_err(|| "Failed to bootstrap logging system") } - -fn start_ipc() -> Result<mock_ipc::IpcServer> { - mock_ipc::IpcServer::start().chain_err(|| "Failed to start IPC server") -} - -fn main_loop(server: mock_ipc::IpcServer) -> Result<()> { - server.wait().chain_err(|| "Error while waiting for server to process") -} diff --git a/mullvad_daemon/src/management_interface.rs b/mullvad_daemon/src/management_interface.rs new file mode 100644 index 0000000000..7e66205862 --- /dev/null +++ b/mullvad_daemon/src/management_interface.rs @@ -0,0 +1,301 @@ +use jsonrpc_core::{Error, ErrorCode, Metadata}; +use jsonrpc_core::futures::{BoxFuture, Future, future, sync}; +use jsonrpc_macros::pubsub; +use jsonrpc_pubsub::{PubSubHandler, PubSubMetadata, Session, SubscriptionId}; +use jsonrpc_ws_server; + +use states::{SecurityState, TargetState}; + +use std::collections::HashMap; +use std::collections::hash_map::Entry; +use std::net::{IpAddr, Ipv4Addr}; +use std::sync::{Arc, Mutex, RwLock, mpsc}; + +use talpid_ipc; +use uuid; + + +pub type AccountToken = String; +pub type CountryCode = String; + +#[derive(Serialize)] +pub struct AccountData { + pub paid_until: String, +} + +#[derive(Serialize)] +pub struct Location { + pub latlong: [f64; 2], + pub country: String, + pub city: String, +} + + +build_rpc_trait! { + pub trait ManagementInterfaceApi { + type Metadata; + + /// Fetches and returns metadata about an account. Returns an error on non-existing + /// accounts. + #[rpc(name = "get_account_data")] + fn get_account_data(&self, AccountToken) -> Result<AccountData, Error>; + + /// Returns available countries. + #[rpc(name = "get_countries")] + fn get_countries(&self) -> Result<HashMap<CountryCode, String>, Error>; + + /// Set which account to connect with + #[rpc(name = "set_account")] + fn set_account(&self, AccountToken) -> Result<(), Error>; + + /// Set which country to connect to + #[rpc(name = "set_country")] + fn set_country(&self, CountryCode) -> Result<(), Error>; + + /// Set if the client should automatically establish a tunnel on start or not. + #[rpc(name = "set_autoconnect")] + fn set_autoconnect(&self, bool) -> Result<(), Error>; + + /// Try to connect if disconnected, or do nothing if already connecting/connected. + #[rpc(name = "connect")] + fn connect(&self) -> Result<(), Error>; + + /// Disconnect the VPN tunnel if it is connecting/connected. Does nothing if already + /// disconnected. + #[rpc(name = "disconnect")] + fn disconnect(&self) -> Result<(), Error>; + + /// Returns the current security state of the Mullvad client. Changes to this state will + /// be announced to subscribers of `event`. + #[rpc(async, name = "get_state")] + fn get_state(&self) -> BoxFuture<SecurityState, Error>; + + /// Returns the current public IP of this computer. + #[rpc(name = "get_ip")] + fn get_ip(&self) -> Result<IpAddr, Error>; + + /// Performs a geoIP lookup and returns the current location as perceived by the public + /// internet. + #[rpc(name = "get_location")] + fn get_location(&self) -> Result<Location, Error>; + + #[pubsub(name = "new_state")] { + /// Subscribes to the `new_state` event notifications. + #[rpc(name = "new_state_subscribe")] + fn new_state_subscribe(&self, Self::Metadata, pubsub::Subscriber<SecurityState>); + + /// Unsubscribes from the `new_state` event notifications. + #[rpc(name = "new_state_unsubscribe")] + fn new_state_unsubscribe(&self, SubscriptionId) -> BoxFuture<(), Error>; + } + } +} + + +/// Enum representing commands coming in on the management interface. +#[derive(Debug)] +pub enum TunnelCommand { + /// Change target state. + SetTargetState(TargetState), + /// Request the current state. + GetState(sync::oneshot::Sender<SecurityState>), +} + +type ActiveSubscriptions = Arc<RwLock<HashMap<SubscriptionId, pubsub::Sink<SecurityState>>>>; + +pub struct ManagementInterfaceServer { + server: talpid_ipc::IpcServer, + active_subscriptions: ActiveSubscriptions, +} + +impl ManagementInterfaceServer { + pub fn start(tunnel_tx: mpsc::Sender<::DaemonEvent>) -> talpid_ipc::Result<Self> { + let rpc = ManagementInterface::new(tunnel_tx); + let active_subscriptions = rpc.active_subscriptions.clone(); + + let mut io = PubSubHandler::default(); + io.extend_with(rpc.to_delegate()); + let server = talpid_ipc::IpcServer::start_with_metadata(io.into(), meta_extractor)?; + Ok( + ManagementInterfaceServer { + server, + active_subscriptions, + }, + ) + } + + pub fn address(&self) -> &str { + self.server.address() + } + + pub fn event_broadcaster(&self) -> EventBroadcaster { + EventBroadcaster { active_subscriptions: self.active_subscriptions.clone() } + } + + /// Consumes the server and waits for it to finish. Returns an error if the server exited + /// due to an error. + pub fn wait(self) -> talpid_ipc::Result<()> { + self.server.wait() + } +} + + +/// A handle that allows broadcasting messages to all subscribers of the management interface. +pub struct EventBroadcaster { + active_subscriptions: ActiveSubscriptions, +} + +impl EventBroadcaster { + /// Sends an event to all subscribers of the management interface. + pub fn notify_new_state(&self, event: SecurityState) { + let active_subscriptions = self.active_subscriptions.read().unwrap(); + for sink in active_subscriptions.values() { + let _ = sink.notify(Ok(event)).wait(); + } + } +} + +struct ManagementInterface { + active_subscriptions: ActiveSubscriptions, + tx: Mutex<mpsc::Sender<::DaemonEvent>>, +} + +impl ManagementInterface { + pub fn new(tx: mpsc::Sender<::DaemonEvent>) -> Self { + ManagementInterface { + active_subscriptions: Default::default(), + tx: Mutex::new(tx), + } + } +} + +impl ManagementInterfaceApi for ManagementInterface { + type Metadata = Meta; + + fn get_account_data(&self, _account_token: AccountToken) -> Result<AccountData, Error> { + trace!("get_account_data"); + Ok(AccountData { paid_until: "2018-12-31T16:00:00.000Z".to_owned() },) + } + + fn get_countries(&self) -> Result<HashMap<CountryCode, String>, Error> { + trace!("get_countries"); + Ok(HashMap::new()) + } + + fn set_account(&self, _account_token: AccountToken) -> Result<(), Error> { + trace!("set_account"); + Ok(()) + } + + fn set_country(&self, _country_code: CountryCode) -> Result<(), Error> { + trace!("set_country"); + Ok(()) + } + + fn set_autoconnect(&self, _autoconnect: bool) -> Result<(), Error> { + trace!("set_autoconnect"); + Ok(()) + } + + fn connect(&self) -> Result<(), Error> { + trace!("connect"); + self.tx + .lock() + .unwrap() + .send(TunnelCommand::SetTargetState(TargetState::Secured).into()) + .map_err(|_| Error::internal_error()) + } + + fn disconnect(&self) -> Result<(), Error> { + trace!("disconnect"); + self.tx + .lock() + .unwrap() + .send(TunnelCommand::SetTargetState(TargetState::Unsecured).into()) + .map_err(|_| Error::internal_error()) + } + + fn get_state(&self) -> BoxFuture<SecurityState, Error> { + trace!("get_state"); + let (state_tx, state_rx) = sync::oneshot::channel(); + match self.tx.lock().unwrap().send(TunnelCommand::GetState(state_tx).into()) { + Ok(()) => state_rx.map_err(|_| Error::internal_error()).boxed(), + Err(_) => future::err(Error::internal_error()).boxed(), + } + } + + fn get_ip(&self) -> Result<IpAddr, Error> { + trace!("get_ip"); + Ok(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4))) + } + + fn get_location(&self) -> Result<Location, Error> { + trace!("get_location"); + Ok( + Location { + latlong: [1.0, 2.0], + country: "narnia".to_owned(), + city: "Le city".to_owned(), + }, + ) + } + + fn new_state_subscribe(&self, + _meta: Self::Metadata, + subscriber: pubsub::Subscriber<SecurityState>) { + trace!("new_state_subscribe"); + let mut active_subscriptions = self.active_subscriptions.write().unwrap(); + loop { + let id = SubscriptionId::String(uuid::Uuid::new_v4().to_string()); + if let Entry::Vacant(entry) = active_subscriptions.entry(id.clone()) { + if let Ok(sink) = subscriber.assign_id(id.clone()) { + debug!("Accepting new subscription with id {:?}", id); + entry.insert(sink); + } + break; + } + } + } + + fn new_state_unsubscribe(&self, id: SubscriptionId) -> BoxFuture<(), Error> { + trace!("new_state_unsubscribe"); + let was_removed = self.active_subscriptions.write().unwrap().remove(&id).is_some(); + let result = if was_removed { + debug!("Unsubscribing id {:?}", id); + future::ok(()) + } else { + future::err( + Error { + code: ErrorCode::InvalidParams, + message: "Invalid subscription".to_owned(), + data: None, + }, + ) + }; + result.boxed() + } +} + + +/// The metadata type. There is one instance associated with each connection. In this pubsub +/// scenario they are created by `meta_extractor` by the server on each new incoming +/// connection. +#[derive(Clone, Debug, Default)] +pub struct Meta { + session: Option<Arc<Session>>, +} + +/// Make the `Meta` type possible to use as jsonrpc metadata type. +impl Metadata for Meta {} + +/// Make the `Meta` type possible to use as a pubsub metadata type. +impl PubSubMetadata for Meta { + fn session(&self) -> Option<Arc<Session>> { + self.session.clone() + } +} + +/// Metadata extractor function for `Meta`. +fn meta_extractor(context: &jsonrpc_ws_server::RequestContext) -> Meta { + Meta { session: Some(Arc::new(Session::new(context.sender()))) } +} diff --git a/mullvad_daemon/src/states.rs b/mullvad_daemon/src/states.rs new file mode 100644 index 0000000000..10e543c58a --- /dev/null +++ b/mullvad_daemon/src/states.rs @@ -0,0 +1,21 @@ +/// Security state of the computer. +/// TODO(linus): There is a difference between lockdown(firewall) and tunnel functionality. The +/// firewall can be set to prevent any leaks but the tunnel is not connected. Then we are secured, +/// but disconnected. The frontend should probably reflect these states in some way. I think it +/// be reasonable to have three states, since unsecured but tunnel is up is probably an invalid +/// state. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum SecurityState { + Unsecured, + Secured, +} + +/// Represents the state the client strives towards. +/// When in `Secured`, the client should keep the computer from leaking and try to +/// establish a VPN tunnel if it is not up. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum TargetState { + Unsecured, + Secured, +} |
