From 03325c939a3f07e68bdc4eb72e4d93505ac79b87 Mon Sep 17 00:00:00 2001 From: Tochukwu Nkemdilim Date: Thu, 16 Aug 2018 23:54:04 +0100 Subject: [PATCH] Chore(Docs): Add More Detailed Documentation --- .../handlers/xml_profile_handler.rs | 4 + src/connectivity/mod.rs | 15 +- src/connectivity/providers/linux.rs | 9 +- src/connectivity/providers/mod.rs | 2 - src/connectivity/providers/osx.rs | 9 +- src/connectivity/providers/windows.rs | 12 +- src/hotspot/mod.rs | 38 ++++- src/hotspot/providers/linux.rs | 141 +++++++++++++++++- src/hotspot/providers/mod.rs | 9 ++ src/hotspot/providers/osx.rs | 6 +- src/hotspot/providers/windows.rs | 68 ++++++--- src/lib.rs | 5 +- src/main.rs | 2 +- src/platforms/linux.rs | 3 + src/platforms/mod.rs | 17 ++- src/platforms/osx.rs | 3 + src/platforms/windows.rs | 11 +- 17 files changed, 294 insertions(+), 60 deletions(-) diff --git a/src/connectivity/handlers/xml_profile_handler.rs b/src/connectivity/handlers/xml_profile_handler.rs index 0ec9656..28cee95 100644 --- a/src/connectivity/handlers/xml_profile_handler.rs +++ b/src/connectivity/handlers/xml_profile_handler.rs @@ -4,17 +4,21 @@ use self::tempfile::NamedTempFile; use connectivity::stubs::windows_wifi_profile; use std::{io, io::Write}; +/// A netowork XML handler for windows, responsible creating +/// disposable xml profiles files. pub(crate) struct NetworkXmlProfileHandler { pub content: String, } impl NetworkXmlProfileHandler { + /// Create a new xml profile handler for windows. pub fn new() -> Self { NetworkXmlProfileHandler { content: NetworkXmlProfileHandler::read_from_stub(), } } + /// Generate a sample templated xml profile. pub fn read_from_stub() -> String { windows_wifi_profile::get_wifi_profile() } diff --git a/src/connectivity/mod.rs b/src/connectivity/mod.rs index 00fec30..1b01700 100644 --- a/src/connectivity/mod.rs +++ b/src/connectivity/mod.rs @@ -7,7 +7,8 @@ mod stubs; use platforms::WifiError; use std::{fmt, io}; -pub trait Network: fmt::Debug { +/// Wireless network connectivity functionality. +pub trait Connectivity: fmt::Debug { /// Makes an attempt to connect to a selected wireless network with password specified. fn connect(&mut self, ssid: &str, password: &str) -> Result; @@ -15,17 +16,19 @@ pub trait Network: fmt::Debug { fn disconnect(&self) -> Result; } +/// Error that occurs when attempting to connect to a wireless network. #[derive(Debug)] pub enum WifiConnectionError { - // SsidNotFound, - // IpAssignFailed, + /// Adding the newtork profile failed. #[cfg(target_os = "windows")] AddNetworkProfileFailed, + /// Failed to connect to wireless network. FailedToConnect(String), + /// Failed to disconnect from wireless network. Try turning the wireless interface down. FailedToDisconnect(String), - Other { - kind: WifiError, - }, + /// A wireless error occurred. + Other { kind: WifiError }, + // SsidNotFound, } impl From for WifiConnectionError { diff --git a/src/connectivity/providers/linux.rs b/src/connectivity/providers/linux.rs index cf64900..dfcbc04 100644 --- a/src/connectivity/providers/linux.rs +++ b/src/connectivity/providers/linux.rs @@ -1,12 +1,14 @@ -use connectivity::{Network, WifiConnectionError}; +use connectivity::{Connectivity, WifiConnectionError}; use platforms::{Connection, WiFi, WifiError, WifiInterface}; use std::process::Command; -impl Network for WiFi { +/// Wireless network connectivity functionality. +impl Connectivity for WiFi { + /// Attempts to connect to a wireless network with a given SSID and password. fn connect(&mut self, ssid: &str, password: &str) -> Result { if !WiFi::is_wifi_enabled().map_err(|err| WifiConnectionError::Other { kind: err })? { return Err(WifiConnectionError::Other { - kind: WifiError::InterfaceDisabled, + kind: WifiError::WifiDisabled, }); } @@ -38,6 +40,7 @@ impl Network for WiFi { Ok(true) } + /// Attempts to disconnect from a wireless network currently connected to. fn disconnect(&self) -> Result { let output = Command::new("nmcli") .args(&["d", "disconnect", "ifname", &self.interface]) diff --git a/src/connectivity/providers/mod.rs b/src/connectivity/providers/mod.rs index acd57ba..c1aefa6 100644 --- a/src/connectivity/providers/mod.rs +++ b/src/connectivity/providers/mod.rs @@ -1,8 +1,6 @@ #[cfg(target_os = "linux")] mod linux; - #[cfg(target_os = "osx")] mod osx; - #[cfg(target_os = "windows")] mod windows; diff --git a/src/connectivity/providers/osx.rs b/src/connectivity/providers/osx.rs index 5a40310..9f51632 100644 --- a/src/connectivity/providers/osx.rs +++ b/src/connectivity/providers/osx.rs @@ -1,12 +1,14 @@ -use connectivity::{Network, WifiConnectionError}; +use connectivity::{Connectivity, WifiConnectionError}; use platforms::{Connection, WiFi, WifiError, WifiInterface}; use std::process::Command; -impl Network for WiFi { +/// Wireless network connectivity functionality. +impl Connectivity for WiFi { + /// Attempts to connect to a wireless network with a given SSID and password. fn connect(&mut self, ssid: &str, password: &str) -> Result { if !WiFi::is_wifi_enabled().map_err(|err| WifiConnectionError::Other { kind: err })? { return Err(WifiConnectionError::Other { - kind: WifiError::InterfaceDisabled, + kind: WifiError::WifiDisabled, }); } @@ -29,6 +31,7 @@ impl Network for WiFi { Ok(true) } + /// Attempts to disconnect from a wireless network currently connected to. fn disconnect(&self) -> Result { let output = Command::new("networksetup") .args(&[ diff --git a/src/connectivity/providers/windows.rs b/src/connectivity/providers/windows.rs index ffce2b2..d6937ad 100644 --- a/src/connectivity/providers/windows.rs +++ b/src/connectivity/providers/windows.rs @@ -1,9 +1,11 @@ use connectivity::handlers::NetworkXmlProfileHandler; -use connectivity::{Network, WifiConnectionError}; +use connectivity::{Connectivity, WifiConnectionError}; use platforms::{Connection, WiFi, WifiError, WifiInterface}; use std::process::Command; impl WiFi { + /// Add the wireless network profile of network to connect to, + /// (this is specific to windows operating system). fn add_profile(ssid: &str, password: &str) -> Result<(), WifiConnectionError> { let mut handler = NetworkXmlProfileHandler::new(); handler.content = handler @@ -13,7 +15,6 @@ impl WiFi { let temp_file = handler.write_to_temp_file()?; - // Add the network profile Command::new("netsh") .args(&[ "wlan", @@ -28,11 +29,13 @@ impl WiFi { } } -impl Network for Windows { +/// Wireless network connectivity functionality. +impl Connectivity for WiFi { + /// Attempts to connect to a wireless network with a given SSID and password. fn connect(&mut self, ssid: &str, password: &str) -> Result { if !WiFi::is_wifi_enabled().map_err(|err| WifiConnectionError::Other { kind: err })? { return Err(WifiConnectionError::Other { - kind: WifiError::InterfaceDisabled, + kind: WifiError::WifiDisabled, }); } @@ -61,6 +64,7 @@ impl Network for Windows { Ok(true) } + /// Attempts to disconnect from a wireless network currently connected to. fn disconnect(&self) -> Result { let output = Command::new("netsh") .args(&["wlan", "disconnect"]) diff --git a/src/hotspot/mod.rs b/src/hotspot/mod.rs index f645fcb..82ccd64 100644 --- a/src/hotspot/mod.rs +++ b/src/hotspot/mod.rs @@ -1,32 +1,54 @@ mod providers; +use self::providers::prelude::HotspotConfig; use platforms::{WifiError, WifiInterface}; -use std::fmt; +use std::{fmt, io}; +/// Error that might occur when interacting managing wireless hotspot. #[derive(Debug)] pub enum WifiHotspotError { + /// Failed to ceate wireless hotspot. CreationFailed, + /// Failed to stop wireless hotspot service. Try turning off + /// the wireless interface via ```wifi.turn_off()```. + FailedToStop(io::Error), + /// A wireless interface error occurred. Other { kind: WifiError }, } -/// Adds support for wifi hotspot functionality +/// Wireless hotspot functionality for a wifi interface. pub trait WifiHotspot: fmt::Debug + WifiInterface { - /// Creates wifi hotspot service for host machine. This only creats the wifi network, + /// Creates wireless hotspot service for host machine. This only creates the wifi network, /// and isn't responsible for initiating the serving of the wifi network process. /// To begin serving the hotspot, use ```start_hotspot()```. - fn create_hotspot(ssid: &str, password: &str) -> Result { + fn create_hotspot( + &mut self, + ssid: &str, + password: &str, + configuration: Option<&HotspotConfig>, + ) -> Result { + let _a = ssid; + let _b = password; + let _c = configuration; + unimplemented!(); } - /// Start serving publicly an already created wifi hotspot. + /// Start serving publicly an already created wireless hotspot. fn start_hotspot() -> Result { unimplemented!(); } - /// Stop serving a wifi network. + /// Stop serving a wireless network. /// - /// > All users connected will automatically be disconnected. - fn stop_hotspot() -> Result { + /// **NOTE: All users connected will automatically be disconnected.** + fn stop_hotspot(&mut self) -> Result { unimplemented!(); } } + +impl From for WifiHotspotError { + fn from(error: WifiError) -> Self { + WifiHotspotError::Other { kind: error } + } +} diff --git a/src/hotspot/providers/linux.rs b/src/hotspot/providers/linux.rs index 263d102..3afc142 100644 --- a/src/hotspot/providers/linux.rs +++ b/src/hotspot/providers/linux.rs @@ -1,4 +1,141 @@ -use hotspot::WifiHotspot; +use hotspot::{WifiHotspot, WifiHotspotError}; use platforms::WiFi; +use std::fmt; +use std::process::Command; -impl WifiHotspot for WiFi {} +/// Name of the group upon which the hotspot would be created. +/// This name must be fixed, in order to still interact with +/// the same hotspot previosuly created. +const HOTSPOT_GROUP: &'static str = "Hotspot"; + +/// Configuration for a wireless hotspot. +pub struct HotspotConfig { + /// The band tor broadcast network on. + band: Option, + /// The channel to broadcast network on. + channel: Option, +} + +#[derive(Debug)] +/// Band type of wireless hotspot. +pub enum HotspotBand { + /// Band `A` + A, + /// Band `BG` + Bg, +} + +#[derive(Debug, Clone, Copy)] +/// Channel to broadcast wireless hotspot on. +pub enum Channel { + /// Channel 1 + One = 1, + /// Channel 2 + Two = 2, + /// Channel 3 + Three = 3, + /// Channel 4 + Four = 4, + /// Channel 5 + Five = 5, + /// Channel 6 + Six = 6, +} + +/// Wireless hotspot functionality for a wifi interface. +impl WifiHotspot for WiFi { + /// Creates wireless hotspot service for host machine. This only creats the wifi network, + /// and isn't responsible for initiating the serving of the wifi network process. + /// To begin serving the hotspot, use ```start_hotspot()```. + fn create_hotspot( + &mut self, + ssid: &str, + password: &str, + configuration: Option<&HotspotConfig>, + ) -> Result { + let mut command = vec![ + "device".to_string(), + "wifi".to_string(), + "ifname".to_string(), + self.interface.to_string(), + "hotspot".to_string(), + "con-name".to_string(), + HOTSPOT_GROUP.to_string(), + "ssid".to_string(), + ssid.to_string(), + "password".to_string(), + password.to_string(), + ]; + + let mut cmd = generate_command_param_from_config(configuration); + command.append(&mut cmd); + + let output = Command::new("nmcli") + .args(&command) + .output() + .map_err(|_err| WifiHotspotError::CreationFailed)?; + + Ok(String::from_utf8_lossy(&output.stdout) + .as_ref() + .contains("successfully activated")) + } + + /// Start serving publicly an already created wireless hotspot. + fn start_hotspot() -> Result { + let output = Command::new("nmcli") + .args(&["con", "up", HOTSPOT_GROUP]) + .output() + .map_err(|err| WifiHotspotError::FailedToStop(err))?; + + Ok(String::from_utf8_lossy(&output.stdout) + .as_ref() + .contains("Connection successfully activated")) + } + + /// Stop serving a wireless network. + /// + /// **NOTE: All users connected will automatically be disconnected.** + fn stop_hotspot(&mut self) -> Result { + let output = Command::new("nmcli") + .args(&["con", "down", HOTSPOT_GROUP]) + .output() + .map_err(|err| WifiHotspotError::FailedToStop(err))?; + + Ok(String::from_utf8_lossy(&output.stdout) + .as_ref() + .contains("Connection 'Hotspot' successfully deactivated")) + } +} + +/// Generate vector values from a given config paramenters. +fn generate_command_param_from_config(configuration: Option<&HotspotConfig>) -> Vec { + let mut command = vec![]; + + if let Some(ref config) = configuration { + if let Some(ref band) = config.band { + let band = format!("{}", band); + let mut a = vec!["band".to_string(), band]; + command.append(&mut a); + } + + if let Some(channel) = config.channel { + let channel = format!("{}", channel as u8); + command.append(&mut vec!["channel".to_string(), channel]); + } + }; + + command +} + +impl fmt::Display for HotspotBand { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{}", + match self { + HotspotBand::A => "a", + HotspotBand::Bg => "bg", + } + ) + } +} diff --git a/src/hotspot/providers/mod.rs b/src/hotspot/providers/mod.rs index 1b93b48..edc0ac9 100644 --- a/src/hotspot/providers/mod.rs +++ b/src/hotspot/providers/mod.rs @@ -6,3 +6,12 @@ mod linux; #[cfg(target_os = "osx")] mod osx; + +pub mod prelude { + #[cfg(target_os = "linux")] + pub use super::linux::*; + #[cfg(target_os = "osx")] + pub use super::osx::*; + #[cfg(target_os = "windows")] + pub use super::windows::*; +} diff --git a/src/hotspot/providers/osx.rs b/src/hotspot/providers/osx.rs index 0a6300d..20c8933 100644 --- a/src/hotspot/providers/osx.rs +++ b/src/hotspot/providers/osx.rs @@ -1,5 +1,9 @@ -use connectivity::{Network, WifiConnectionError}; +use connectivity::{Connectivity, WifiConnectionError}; use platforms::WiFi; use std::process::Command; +/// Configuration for a wireless hotspot. +pub struct HotspotConfig {} + +/// Wireless hotspot functionality for a wifi interface. impl WifiHotspot for WiFi {} diff --git a/src/hotspot/providers/windows.rs b/src/hotspot/providers/windows.rs index a592c60..4686eb1 100644 --- a/src/hotspot/providers/windows.rs +++ b/src/hotspot/providers/windows.rs @@ -1,12 +1,32 @@ -use connectivity::handlers::NetworkXmlProfileHandler; -use connectivity::{ - Network, WifiConnectionError, WifiError, WifiHotspot, WifiHotspotError, WifiInterface, -}; -use platforms::WiFi; +use hotspot::{WifiHotspot, WifiHotspotError}; +use platforms::{WiFi, WifiError, WifiInterface}; use std::process::Command; +/// Configuration for a wireless hotspot. +pub struct HotspotConfig {} + +impl WiFi { + /// Attempts to turn on a wireless networ if down. + fn try_turn_on_network_if_down() -> Result<(), WifiError> { + if !Self::is_wifi_enabled()? { + Self::turn_on().map_err(|err| WifiError::InterfaceFailedToOn)?; + } + + Ok(()) + } +} + +/// Wireless hotspot functionality for a wifi interface. impl WifiHotspot for WiFi { - fn create_hotspot(ssid: &str, password: &str) -> Result { + /// Creates wireless hotspot service for host machine. This only creats the wifi network, + /// and isn't responsible for initiating the serving of the wifi network process. + /// To begin serving the hotspot, use ```start_hotspot()```. + fn create_hotspot( + &mut self, + ssid: &str, + password: &str, + configuration: Option<&HotspotConfig>, + ) -> Result { let output = Command::new("netsh") .args(&[ "wlan", @@ -17,21 +37,14 @@ impl WifiHotspot for WiFi { &format!("key={}", password), ]) .output() - .map_err(|err| WifiHotspotError::CreationFailed)?; + .map_err(|_err| WifiHotspotError::CreationFailed)?; - Ok(String::from_utf8_lossy(&output.stdout) + if !String::from_utf8_lossy(&output.stdout) .as_ref() - .contains("successfully changed")) - } + .contains("successfully changed") + {} - fn start_hotspot() -> Result { - if !Self::is_wifi_enabled() { - if !Self::turn_on().map_err(|err| WifiHotspotError::Other { kind: err })? { - return Err(WifiHotspotError::Other { - kind: WifiError::InterfaceFailedToOn, - }); - } - } + Self::try_turn_on_network_if_down()?; let output = Command::new("netsh") .args(&["wlan", "start", "hostednetwork"]) @@ -43,7 +56,24 @@ impl WifiHotspot for WiFi { .contains("hosted network started")) } - fn stop_hotspot() -> Result { + /// Start serving publicly an already created wireless hotspot. + fn start_hotspot() -> Result { + Self::try_turn_on_network_if_down()?; + + let output = Command::new("netsh") + .args(&["wlan", "start", "hostednetwork"]) + .output() + .map_err(|err| WifiHotspotError::CreationFailed)?; + + Ok(String::from_utf8_lossy(&output.stdout) + .as_ref() + .contains("hosted network started")) + } + + /// Stop serving a wireless network. + /// + /// **NOTE: All users connected will automatically be disconnected.** + fn stop_hotspot(&mut self) -> Result { let output = Command::new("netsh") .args(&["wlan", "stop", "hostednetwork"]) .output() diff --git a/src/lib.rs b/src/lib.rs index 9413012..36ca433 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,15 @@ #![allow(dead_code)] mod connectivity; +#[cfg(target_os = "windows")] +mod handler; mod hotspot; mod platforms; +/// Pre-requisite module for `Connectivity`, `Hotspot` functionality. pub mod prelude { pub use connectivity::*; pub use hotspot::*; } -pub use platforms::*; +pub use platforms::WiFi; diff --git a/src/main.rs b/src/main.rs index 6d14bd1..92f1082 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ mod connectivity; mod hotspot; mod platforms; -use connectivity::{Network, WifiConnectionError}; +use connectivity::{Connectivity, WifiConnectionError}; use platforms::{Config, WiFi}; fn main() -> Result<(), WifiConnectionError> { diff --git a/src/platforms/linux.rs b/src/platforms/linux.rs index 387a09d..62d20e3 100644 --- a/src/platforms/linux.rs +++ b/src/platforms/linux.rs @@ -6,6 +6,7 @@ pub struct Connection { pub(crate) ssid: String, } +/// Wireless network interface for linux operating system. #[derive(Debug)] pub struct Linux { pub(crate) connection: Option, @@ -23,6 +24,8 @@ impl Linux { } } +/// Wifi interface for linux operating system. +/// This provides basic functionalities for wifi interface. impl WifiInterface for Linux { fn is_wifi_enabled() -> Result { let output = Command::new("nmcli") diff --git a/src/platforms/mod.rs b/src/platforms/mod.rs index f95a5cd..d9c661e 100644 --- a/src/platforms/mod.rs +++ b/src/platforms/mod.rs @@ -17,32 +17,35 @@ use std::{fmt, io}; /// Configuration for a wifi network. #[derive(Debug, Clone)] pub struct Config<'a> { + /// The interface the wifi module is situated. pub interface: Option<&'a str>, } #[derive(Debug)] pub enum WifiError { - // OsNotSupported, - InterfaceDisabled, - + // The specified wifi is currently disabled. Try switching it on. + WifiDisabled, + /// The wifi interface interface failed to switch on. #[cfg(target_os = "windows")] InterfaceFailedToOn, - + /// IO Error occurred. IoError(io::Error), } +/// Wifi interface for an operating system. +/// This provides basic functionalities for wifi interface. pub trait WifiInterface: fmt::Debug { - /// Checks if the wifi interface on host machine is enables. + /// Check if the wifi interface on host machine is enabled. fn is_wifi_enabled() -> Result { unimplemented!(); } - /// Turns on the wifi interface of host machine. + /// Turn on the wifi interface of host machine. fn turn_on() -> Result<(), WifiError> { unimplemented!(); } - // Turns off the wifi interface of host machine. + /// Turn off the wifi interface of host machine. fn turn_off() -> Result<(), WifiError> { unimplemented!(); } diff --git a/src/platforms/osx.rs b/src/platforms/osx.rs index 7c22a93..39d3e49 100644 --- a/src/platforms/osx.rs +++ b/src/platforms/osx.rs @@ -6,6 +6,7 @@ pub struct Connection { pub(crate) ssid: String, } +/// Wireless network interface for mac operating system. #[derive(Debug)] pub struct Osx { pub(crate) connection: Option, @@ -23,6 +24,8 @@ impl Osx { } } +/// Wifi interface for osx operating system. +/// This provides basic functionalities for wifi interface. impl WifiInterface for Osx { fn is_wifi_enabled() -> Result { let output = Command::new("networksetup") diff --git a/src/platforms/windows.rs b/src/platforms/windows.rs index b0937a1..5c7f23c 100644 --- a/src/platforms/windows.rs +++ b/src/platforms/windows.rs @@ -1,11 +1,14 @@ -use platforms::{WifiError, WifiInterface}; -use std::collections::HashMap; +use platforms::Config; +// use platforms::WifiError; +use platforms::WifiInterface; +// use std::process::Command; #[derive(Debug)] pub struct Connection { pub(crate) ssid: String, } +/// Wireless network interface for windows operating system. #[derive(Debug)] pub struct Windows { pub(crate) connection: Option, @@ -13,7 +16,7 @@ pub struct Windows { } impl Windows { - pub fn new(name: &str, config: Option) -> Self { + pub fn new(config: Option) -> Self { Windows { connection: None, interface: config.map_or("wlan0".to_string(), |cfg| { @@ -23,4 +26,6 @@ impl Windows { } } +/// Wifi interface for windows operating system. +/// This provides basic functionalities for wifi interface. impl WifiInterface for Windows {}