diff options
author | yossarian <sergiybiluk@gmail.com> | 2020-03-01 13:17:00 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-01 13:17:00 +0100 |
commit | c45b3c82bf17c2e8f2a0ae4e9b611139c1d55d79 (patch) | |
tree | 9701742c4fb3618dc4f36eaa557c2756a82035e4 /src/os/shared.rs | |
parent | 5bd64ddac0fb4b98e71212c4acace065e7fe9daf (diff) |
fix(error-handling): add custom error handling (#104)
* Initial
* Add errors file
* Update
* Add error message
* Update
* Add kind method
* Update error kind
* Update get_datalink_channel
* Update unused var
* Initial
* Add errors file
* Update
* Add error message
* Update
* Add kind method
* Update error kind
* Update error message
* Update error name
* Update error messages
* Update message
* Update
* Update error message
* format
* format2
* update
* Update error checking
* format
* refactor
* reduce message
* remove unused code
* fix lint
* wip
* add multiline
* add handle_errors
* update fold
* update
* clippy
* Update
* spaces
* fix(error-handling): display interface names in errors
* style(format): rustfmt
Co-authored-by: Aram Drevekenin <aram@poor.dev>
Diffstat (limited to 'src/os/shared.rs')
-rw-r--r-- | src/os/shared.rs | 107 |
1 files changed, 93 insertions, 14 deletions
diff --git a/src/os/shared.rs b/src/os/shared.rs index c509f91..64d26d5 100644 --- a/src/os/shared.rs +++ b/src/os/shared.rs @@ -1,14 +1,14 @@ use ::pnet_bandwhich_fork::datalink::Channel::Ethernet; use ::pnet_bandwhich_fork::datalink::DataLinkReceiver; use ::pnet_bandwhich_fork::datalink::{self, Config, NetworkInterface}; -use ::std::io::{self, stdin, Write}; +use ::std::io::{self, stdin, ErrorKind, Write}; use ::termion::event::Event; use ::termion::input::TermRead; use ::tokio::runtime::Runtime; -use ::std::io::ErrorKind; use ::std::time; +use crate::os::errors::GetInterfaceErrorKind; use signal_hook::iterator::Signals; #[cfg(target_os = "linux")] @@ -34,17 +34,25 @@ impl Iterator for KeyboardEvents { fn get_datalink_channel( interface: &NetworkInterface, -) -> Result<Box<dyn DataLinkReceiver>, std::io::Error> { +) -> Result<Box<dyn DataLinkReceiver>, GetInterfaceErrorKind> { let mut config = Config::default(); config.read_timeout = Some(time::Duration::new(1, 0)); match datalink::channel(interface, config) { Ok(Ethernet(_tx, rx)) => Ok(rx), - Ok(_) => Err(std::io::Error::new( - ErrorKind::Other, - "Unsupported interface type", - )), - Err(e) => Err(e), + Ok(_) => Err(GetInterfaceErrorKind::OtherError(format!( + "{}: Unsupported interface type", + interface.name + ))), + Err(e) => match e.kind() { + ErrorKind::PermissionDenied => Err(GetInterfaceErrorKind::PermissionError( + interface.name.to_owned(), + )), + _ => Err(GetInterfaceErrorKind::OtherError(format!( + "{}: {}", + &interface.name, e + ))), + }, } } @@ -82,6 +90,79 @@ fn create_write_to_stdout() -> Box<dyn FnMut(String) + Send> { }) } +#[derive(Debug)] +pub struct UserErrors { + permission: Option<String>, + other: Option<String>, +} + +pub fn collect_errors<'a, I>(network_frames: I) -> String +where + I: Iterator< + Item = ( + &'a NetworkInterface, + Result<Box<dyn DataLinkReceiver>, GetInterfaceErrorKind>, + ), + >, +{ + let errors = network_frames.fold( + UserErrors { + permission: None, + other: None, + }, + |acc, (_, elem)| { + if let Some(iface_error) = elem.err() { + match iface_error { + GetInterfaceErrorKind::PermissionError(interface_name) => { + if let Some(prev_interface) = acc.permission { + return UserErrors { + permission: Some(format!("{}, {}", prev_interface, interface_name)), + ..acc + }; + } else { + return UserErrors { + permission: Some(interface_name), + ..acc + }; + } + } + error => { + if let Some(prev_errors) = acc.other { + return UserErrors { + other: Some(format!("{} \n {}", prev_errors, error)), + ..acc + }; + } else { + return UserErrors { + other: Some(format!("{}", error)), + ..acc + }; + } + } + }; + } + acc + }, + ); + if let Some(interface_name) = errors.permission { + if let Some(other_errors) = errors.other { + format!( + "\n\n{}: {} \nAdditional Errors: \n {}", + interface_name, + eperm_message(), + other_errors + ) + } else { + format!("\n\n{}: {}", interface_name, eperm_message()) + } + } else { + let other_errors = errors + .other + .expect("asked to collect errors but found no errors"); + format!("\n\n {}", other_errors) + } +} + pub fn get_input( interface_name: &Option<String>, resolve: bool, @@ -121,13 +202,11 @@ pub fn get_input( }; if available_network_frames.is_empty() { - for (_, iface) in network_frames { - if let Some(iface_error) = iface.err() { - if let ErrorKind::PermissionDenied = iface_error.kind() { - failure::bail!(eperm_message()) - } - } + let all_errors = collect_errors(network_frames.clone()); + if !all_errors.is_empty() { + failure::bail!(all_errors); } + failure::bail!("Failed to find any network interface to listen on."); } |