diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2017-10-30 14:59:46 +0100 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2017-10-30 14:59:46 +0100 |
| commit | 3df28edf3258b3de877a14becac237e413978e02 (patch) | |
| tree | d5dc489b8d3360bafcaa7b6eae1bd59e0be5f749 /mullvad-daemon/src | |
| parent | a9379bf7c5628abdac284857c200e9f19346ef29 (diff) | |
| parent | 7cce6e4f1f3d3b088ae383673881067f90b09443 (diff) | |
| download | mullvadvpn-3df28edf3258b3de877a14becac237e413978e02.tar.xz mullvadvpn-3df28edf3258b3de877a14becac237e413978e02.zip | |
Merge branch 'problem-report-send'
Diffstat (limited to 'mullvad-daemon/src')
| -rw-r--r-- | mullvad-daemon/src/bin/problem-report.rs | 116 | ||||
| -rw-r--r-- | mullvad-daemon/src/main.rs | 13 | ||||
| -rw-r--r-- | mullvad-daemon/src/management_interface.rs | 10 | ||||
| -rw-r--r-- | mullvad-daemon/src/master.rs | 16 |
4 files changed, 65 insertions, 90 deletions
diff --git a/mullvad-daemon/src/bin/problem-report.rs b/mullvad-daemon/src/bin/problem-report.rs index a4b5107dec..8ecae0a0e5 100644 --- a/mullvad-daemon/src/bin/problem-report.rs +++ b/mullvad-daemon/src/bin/problem-report.rs @@ -11,6 +11,8 @@ extern crate clap; #[macro_use] extern crate error_chain; +extern crate mullvad_rpc; + use error_chain::ChainedError; use std::cmp::min; use std::fmt; @@ -20,6 +22,9 @@ use std::path::{Path, PathBuf}; /// Maximum number of bytes to read from each log file const LOG_MAX_READ_BYTES: usize = 5 * 1024 * 1024; +/// Maximum number of bytes allowed in a report. +const REPORT_MAX_SIZE: usize = 4 * LOG_MAX_READ_BYTES; + /// Field delimeter in generated problem report const LOG_DELIMITER: &'static str = "===================="; @@ -34,6 +39,9 @@ error_chain!{ description("Error reading the contents of log file") display("Error reading the contents of log file: {}", path.to_string_lossy()) } + RpcError { + description("Error during RPC call") + } } } @@ -96,40 +104,40 @@ fn run() -> Result<()> { let matches = app.get_matches(); if let Some(collect_matches) = matches.subcommand_matches("collect") { - let log_paths = values_t!(collect_matches.values_of("logs"), String) - .unwrap_or(Vec::new()) - .iter() - .map(PathBuf::from) - .collect(); - let output_path = value_t_or_exit!(collect_matches.value_of("output"), String); - collect_report(log_paths, PathBuf::from(output_path)) + let log_paths = collect_matches + .values_of_os("logs") + .map(|os_values| os_values.map(Path::new).collect()) + .unwrap_or(Vec::new()); + let output_path = Path::new(collect_matches.value_of_os("output").unwrap()); + collect_report(&log_paths, output_path) } else if let Some(send_matches) = matches.subcommand_matches("send") { - let report_path = value_t_or_exit!(send_matches.value_of("report"), String); - let user_email = value_t!(send_matches.value_of("email"), String).unwrap_or(String::new()); - let user_message = - value_t!(send_matches.value_of("message"), String).unwrap_or(String::new()); - send_problem_report(user_email, user_message, PathBuf::from(report_path)) + let report_path = Path::new(send_matches.value_of_os("report").unwrap()); + let user_email = send_matches.value_of("email").unwrap_or(""); + let user_message = send_matches.value_of("message").unwrap_or(""); + send_problem_report(user_email, user_message, report_path) } else { unreachable!("No sub command given"); } } -fn collect_report(log_paths: Vec<PathBuf>, save_path: PathBuf) -> Result<()> { +fn collect_report(log_paths: &[&Path], output_path: &Path) -> Result<()> { let mut problem_report = ProblemReport::default(); - for log_path in log_paths.into_iter() { - problem_report.add_file_log(log_path); + for log_path in log_paths { + problem_report.add_log(log_path); } - write_problem_report(&save_path, problem_report) - .chain_err(|| ErrorKind::WriteReportError(save_path.clone())) + write_problem_report(&output_path, problem_report) + .chain_err(|| ErrorKind::WriteReportError(output_path.to_path_buf())) } -fn send_problem_report( - _user_email: String, - _user_message: String, - _report_path: PathBuf, -) -> Result<()> { - // TODO: Implement submission to master - Ok(()) +fn send_problem_report(user_email: &str, user_message: &str, report_path: &Path) -> Result<()> { + let report_content = read_file_lossy(report_path, REPORT_MAX_SIZE) + .chain_err(|| ErrorKind::ReadLogError(report_path.to_path_buf()))?; + let mut rpc_client = + mullvad_rpc::ProblemReportProxy::connect().chain_err(|| ErrorKind::RpcError)?; + rpc_client + .problem_report(user_email, user_message, &report_content) + .call() + .chain_err(|| ErrorKind::RpcError) } fn write_problem_report(path: &Path, problem_report: ProblemReport) -> io::Result<()> { @@ -147,42 +155,14 @@ struct ProblemReport { } impl ProblemReport { - /// Attach file log to this report - /// Unlike `try_add_file_log` this method uses the error description - /// instead of log contents if error occurred when reading log file. - fn add_file_log(&mut self, path: PathBuf) { - if let Err(e) = self.try_add_file_log(&path) - .chain_err(|| ErrorKind::ReadLogError(path.clone())) - { - self.logs.push(( - path.to_string_lossy().into_owned(), - e.display_chain().to_string(), - )); - } - } - - /// Try reading log from file source and attach it to this report - fn try_add_file_log(&mut self, path: &Path) -> io::Result<()> { - Ok(self.logs.push(( - path.to_string_lossy().into_owned(), - Self::read_log_file(path, LOG_MAX_READ_BYTES)?, - ))) - } - - /// Private helper to safely read the given number of bytes off the tail of UTF-8 log file - /// and return it as a string - fn read_log_file(path: &Path, max_bytes: usize) -> io::Result<String> { - let mut file = File::open(path)?; - let file_size = file.metadata()?.len(); - - if file_size > max_bytes as u64 { - file.seek(SeekFrom::Start(file_size - max_bytes as u64))?; - } - - let capacity = min(file_size, max_bytes as u64) as usize; - let mut buffer = Vec::with_capacity(capacity); - file.take(max_bytes as u64).read_to_end(&mut buffer)?; - Ok(String::from_utf8_lossy(&buffer).into_owned()) + /// Attach file log to this report. This method uses the error chain instead of log + /// contents if error occurred when reading log file. + fn add_log(&mut self, path: &Path) { + let content = read_file_lossy(path, LOG_MAX_READ_BYTES) + .chain_err(|| ErrorKind::ReadLogError(path.to_path_buf())) + .unwrap_or_else(|e| e.display_chain().to_string()); + self.logs + .push((path.to_string_lossy().into_owned(), content)); } } @@ -198,3 +178,19 @@ impl fmt::Display for ProblemReport { Ok(()) } } + +/// Helper to lossily read a file to a `String`. If the file size exceeds the given `max_bytes`, +/// only the last `max_bytes` bytes of the file are read. +fn read_file_lossy(path: &Path, max_bytes: usize) -> io::Result<String> { + let mut file = File::open(path)?; + let file_size = file.metadata()?.len(); + + if file_size > max_bytes as u64 { + file.seek(SeekFrom::Start(file_size - max_bytes as u64))?; + } + + let capacity = min(file_size, max_bytes as u64) as usize; + let mut buffer = Vec::with_capacity(capacity); + file.take(max_bytes as u64).read_to_end(&mut buffer)?; + Ok(String::from_utf8_lossy(&buffer).into_owned()) +} diff --git a/mullvad-daemon/src/main.rs b/mullvad-daemon/src/main.rs index e804dcace8..ad2850b926 100644 --- a/mullvad-daemon/src/main.rs +++ b/mullvad-daemon/src/main.rs @@ -20,9 +20,6 @@ extern crate serde; #[macro_use] extern crate serde_derive; -#[macro_use] -extern crate jsonrpc_client_core; -extern crate jsonrpc_client_http; extern crate jsonrpc_core; #[macro_use] extern crate jsonrpc_macros; @@ -32,6 +29,7 @@ extern crate jsonrpc_ws_server; extern crate lazy_static; extern crate uuid; +extern crate mullvad_rpc; extern crate mullvad_types; extern crate talpid_core; extern crate talpid_ipc; @@ -39,7 +37,6 @@ extern crate talpid_types; mod cli; mod management_interface; -mod master; mod rpc_info; mod settings; mod shutdown; @@ -47,10 +44,9 @@ mod shutdown; use error_chain::ChainedError; use futures::Future; -use jsonrpc_client_http::HttpHandle; use jsonrpc_core::futures::sync::oneshot::Sender as OneshotSender; use management_interface::{BoxFuture, ManagementInterfaceServer, TunnelCommand}; -use master::AccountsProxy; +use mullvad_rpc::{AccountsProxy, HttpHandle}; use mullvad_types::account::{AccountData, AccountToken}; use mullvad_types::relay_endpoint::RelayEndpoint; use mullvad_types::states::{DaemonState, SecurityState, TargetState}; @@ -206,8 +202,7 @@ impl Daemon { tx, management_interface_broadcaster, settings: settings::Settings::load().chain_err(|| "Unable to read settings")?, - accounts_proxy: master::create_account_proxy() - .chain_err(|| "Unable to bootstrap RPC client")?, + accounts_proxy: AccountsProxy::connect().chain_err(|| "Unable to connect RPC client")?, firewall: FirewallProxy::new().chain_err(|| ErrorKind::FirewallError)?, relay_endpoint: None, tunnel_metadata: None, @@ -339,7 +334,7 @@ impl Daemon { fn on_get_account_data( &mut self, - tx: OneshotSender<BoxFuture<AccountData, jsonrpc_client_core::Error>>, + tx: OneshotSender<BoxFuture<AccountData, mullvad_rpc::Error>>, account_token: AccountToken, ) { let rpc_call = self.accounts_proxy diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index 829f843fca..43e55f4cb4 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -1,13 +1,13 @@ use error_chain; use error_chain::ChainedError; -use jsonrpc_client_core; use jsonrpc_core::{Error, ErrorCode, Metadata}; use jsonrpc_core::futures::{future, sync, Future}; use jsonrpc_core::futures::sync::oneshot::Sender as OneshotSender; use jsonrpc_macros::pubsub; use jsonrpc_pubsub::{PubSubHandler, PubSubMetadata, Session, SubscriptionId}; use jsonrpc_ws_server; +use mullvad_rpc; use mullvad_types::account::{AccountData, AccountToken}; use mullvad_types::location::{CountryCode, Location}; use mullvad_types::relay_endpoint::RelayEndpoint; @@ -126,7 +126,7 @@ pub enum TunnelCommand { GetState(OneshotSender<DaemonState>), /// Request the metadata for an account. GetAccountData( - OneshotSender<BoxFuture<AccountData, jsonrpc_client_core::Error>>, + OneshotSender<BoxFuture<AccountData, mullvad_rpc::Error>>, AccountToken, ), /// Set which account token to use for subsequent connection attempts. @@ -283,9 +283,9 @@ impl<T: From<TunnelCommand> + 'static + Send> ManagementInterface<T> { /// Converts the given error to an error that can be given to the caller of the API. /// Will let any actual RPC error through as is, any other error is changed to an internal /// error. - fn map_rpc_error(error: jsonrpc_client_core::Error) -> Error { + fn map_rpc_error(error: mullvad_rpc::Error) -> Error { match error.kind() { - &jsonrpc_client_core::ErrorKind::JsonRpcError(ref rpc_error) => { + &mullvad_rpc::ErrorKind::JsonRpcError(ref rpc_error) => { // We have to manually copy the error since we have different // versions of the jsonrpc_core library at the moment. Error { @@ -344,7 +344,7 @@ impl<T: From<TunnelCommand> + 'static + Send> ManagementInterfaceApi for Managem let future = self.send_command_to_daemon(TunnelCommand::GetAccountData(tx, account_token)) .and_then(|_| rx.map_err(|_| Error::internal_error())) .and_then(|rpc_future| { - rpc_future.map_err(|error: jsonrpc_client_core::Error| { + rpc_future.map_err(|error: mullvad_rpc::Error| { error!( "Unable to get account data from master: {}", error.display_chain() diff --git a/mullvad-daemon/src/master.rs b/mullvad-daemon/src/master.rs deleted file mode 100644 index 37bfbe65e5..0000000000 --- a/mullvad-daemon/src/master.rs +++ /dev/null @@ -1,16 +0,0 @@ -use chrono::DateTime; -use chrono::offset::Utc; -use jsonrpc_client_http::{Error as HttpError, HttpHandle, HttpTransport}; - -use mullvad_types::account::AccountToken; - -static MASTER_API_URI: &str = "https://api.mullvad.net/rpc/"; - -pub fn create_account_proxy() -> Result<AccountsProxy<HttpHandle>, HttpError> { - let transport = HttpTransport::new()?.handle(MASTER_API_URI)?; - Ok(AccountsProxy::new(transport)) -} - -jsonrpc_client!(pub struct AccountsProxy { - pub fn get_expiry(&mut self, account_token: AccountToken) -> RpcRequest<DateTime<Utc>>; -}); |
