diff --git a/src/connectivity/providers/osx.rs b/src/connectivity/providers/osx.rs new file mode 100644 index 0000000..6321a96 --- /dev/null +++ b/src/connectivity/providers/osx.rs @@ -0,0 +1,85 @@ +use connectivity::{Network, WifiConnectionError}; +use std::process::Command; + +#[derive(Debug)] +pub struct OSX { + pub name: String, + interface: String, +} + +impl OSX { + #[cfg(target_os = "windows")] + pub fn new(name: &str, interface: Option<&str>) -> Self { + OSX { + name: name.into(), + interface: interface.unwrap_or("en0").into(), + } + } +} + +impl Network for OSX { + fn connect(&self, password: &str) -> Result { + let output = Command::new("networksetup") + .args(&["-setairportnetwork", &self.interface, &self.name, &password]) + .output() + .map_err(|err| WifiConnectionError::FailedToConnect(format!("{}", err)))?; + + Ok(String::from_utf8_lossy(&output.stdout) + .as_ref() + .contains("successfully activated")) + } + + fn disconnect(&self) -> Result { + let output = Command::new("networksetup") + .args(&[ + "-removepreferredwirelessnetwork", + &self.interface, + &self.name, + ]) + .output() + .map_err(|err| WifiConnectionError::FailedToDisconnect(format!("{}", err)))?; + + Ok(String::from_utf8_lossy(&output.stdout) + .as_ref() + .contains("disconnect")) + } + + fn is_wifi_enabled(&self) -> bool { + let output = Command::new("networksetup") + .args(&["radio", "wifi"]) + .output(); + + if let Err(_) = output { + return false; + } + + String::from_utf8_lossy(&output.unwrap().stdout) + .replace(" ", "") + .replace("\n", "") + .contains("enabled") + } + + fn connnection_up(&self) -> bool { + let output = Command::new("networksetup") + .args(&["-setairportpower", &self.interface, "on"]) + .output(); + + if let Err(_) = output { + return false; + } + + false + } + + fn connnection_down(&self) -> bool { + let output = Command::new("networksetup") + .args(&["-setairportpower", &self.interface, "off"]) + .output(); + + if let Err(_) = output { + return false; + } + + false + } +} diff --git a/src/hotspot/mod.rs b/src/hotspot/mod.rs new file mode 100644 index 0000000..3b3747c --- /dev/null +++ b/src/hotspot/mod.rs @@ -0,0 +1,27 @@ +mod providers; + +// pub use self::providers::Machine; +use platforms::{WifiError, WifiInterface}; +use std::fmt; + +#[derive(Debug)] +pub enum WifiHotspotError { + CreationFailed, + Other { kind: WifiError }, +} + +/// Adds support for wifi hotspot functionality +pub trait WifiHotspot: fmt::Debug + WifiInterface { + /// Creates wifi 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(ssid: &str, password: &str) -> Result; + + /// Start serving publicly an already created wifi hotspot. + fn start_hotspot() -> Result; + + /// Stop serving a wifi network. + /// + /// > All users connected will automatically be disconnected. + fn stop_hotspot() -> Result; +} diff --git a/src/hotspot/providers/linux.rs b/src/hotspot/providers/linux.rs new file mode 100644 index 0000000..8101d69 --- /dev/null +++ b/src/hotspot/providers/linux.rs @@ -0,0 +1,31 @@ +use hotspot::{WifiHotspot, WifiHotspotError}; +use platforms::Linux; + +// #[derive(Debug)] +// pub struct Linux { +// pub name: String, +// interface: String, +// } + +// impl Linux { +// pub fn new(name: &str, interface: Option<&str>) -> Self { +// Linux { +// name: name.into(), +// interface: interface.unwrap_or("wlan0").into(), +// } +// } +// } + +impl WifiHotspot for Linux { + fn create_hotspot(ssid: &str, password: &str) -> Result { + unimplemented!(); + } + + fn start_hotspot() -> Result { + unimplemented!(); + } + + fn stop_hotspot() -> Result { + unimplemented!(); + } +} diff --git a/src/hotspot/providers/mod.rs b/src/hotspot/providers/mod.rs new file mode 100644 index 0000000..267043e --- /dev/null +++ b/src/hotspot/providers/mod.rs @@ -0,0 +1,14 @@ +// #[cfg(target_os = "windows")] +// mod windows; +// #[cfg(target_os = "windows")] +// pub use self::windows::Windows as Machine; + +// #[cfg(target_os = "linux")] +// mod linux; +// #[cfg(target_os = "linux")] +// pub use self::linux as Machine; + +// #[cfg(target_os = "osx")] +// mod osx; +// #[cfg(target_os = "osx")] +// pub use self::osx::OSX as Machine; diff --git a/src/hotspot/providers/osx.rs b/src/hotspot/providers/osx.rs new file mode 100644 index 0000000..98174c2 --- /dev/null +++ b/src/hotspot/providers/osx.rs @@ -0,0 +1,18 @@ +use connectivity::{Network, WifiConnectionError}; +use std::process::Command; + +#[derive(Debug)] +pub struct OSX { + pub name: String, + interface: String, +} + +impl OSX { + #[cfg(target_os = "windows")] + pub fn new(name: &str, interface: Option<&str>) -> Self { + OSX { + name: name.into(), + interface: interface.unwrap_or("en0").into(), + } + } +} diff --git a/src/hotspot/providers/windows.rs b/src/hotspot/providers/windows.rs new file mode 100644 index 0000000..3e9ea86 --- /dev/null +++ b/src/hotspot/providers/windows.rs @@ -0,0 +1,61 @@ +use connectivity::handlers::NetworkXmlProfileHandler; +use connectivity::{ + Network, WifiConnectionError, WifiError, WifiHotspot, WifiHotspotError, WifiInterface, +}; +use platforms::Windows; +use std::process::Command; + +// #[derive(Debug)] +// pub(crate) struct Windows { +// name: String, +// } + +impl WifiHotspot for Windows { + fn create_hotspot(ssid: &str, password: &str) -> Result { + let output = Command::new("netsh") + .args(&[ + "wlan", + "set", + "hostednetwork", + "mode = allow", + &format!("ssid={}", ssid), + &format!("key={}", password), + ]) + .output() + .map_err(|err| WifiHotspotError::CreationFailed)?; + + Ok(String::from_utf8_lossy(&output.stdout) + .as_ref() + .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, + }); + } + } + + 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")) + } + + fn stop_hotspot() -> Result { + let output = Command::new("netsh") + .args(&["wlan", "stop", "hostednetwork"]) + .output() + .map_err(|err| WifiHotspotError::CreationFailed)?; + + return Ok(String::from_utf8_lossy(&output.stdout) + .as_ref() + .contains("hosted network stopped")); + } +} diff --git a/src/platforms/linux.rs b/src/platforms/linux.rs new file mode 100644 index 0000000..1983584 --- /dev/null +++ b/src/platforms/linux.rs @@ -0,0 +1,58 @@ +use platforms::{WifiError, WifiInterface}; +use std::collections::HashMap; +use std::process::Command; + +#[derive(Debug)] +pub(crate) struct Connection { + pub ssid: String, +} + +#[derive(Debug)] +pub(crate) struct Linux { + hotspot: Option>, + pub connection: Option, + pub interface: String, +} + +impl Linux { + pub fn new(name: &str, interface: Option<&str>) -> Self { + Linux { + hotspot: None, + connection: None, + interface: String::from("wlan0"), + } + } +} + +impl WifiInterface for Linux { + fn is_wifi_enabled() -> bool { + let output = Command::new("nmcli").args(&["radio", "wifi"]).output(); + + if let Err(_) = output { + return false; + } + + String::from_utf8_lossy(&output.unwrap().stdout) + .replace(" ", "") + .replace("\n", "") + .contains("enabled") + } + + fn turn_on() -> Result { + let _output = Command::new("nmcli") + .args(&["radio", "wifi", "on"]) + .output() + .map_err(|err| WifiError::IoError(err))?; + + Ok(true) + } + + fn turn_off() -> Result { + let _output = Command::new("nmcli") + .args(&["radio", "wifi", "off"]) + .output() + .map_err(|err| WifiError::IoError(err))?; + + Ok(true) + } +} diff --git a/src/platforms/mod.rs b/src/platforms/mod.rs new file mode 100644 index 0000000..9266b27 --- /dev/null +++ b/src/platforms/mod.rs @@ -0,0 +1,38 @@ +#[cfg(target_os = "linux")] +mod linux; + +#[cfg(target_os = "osx")] +mod osx; + +// #[cfg(target_os = "windows")] +mod windows; + +#[cfg(target_os = "linux")] +pub(crate) use self::linux::{Connection, Linux}; + +#[cfg(target_os = "osx")] +pub use self::osx::OSX; + +// #[cfg(target_os = "windows")] +pub use self::windows::Windows; + +use std::{fmt, io}; + +#[derive(Debug)] +pub enum WifiError { + OsNotSupported, + InterfaceDisabled, + InterfaceFailedToOn, + IoError(io::Error), +} + +pub trait WifiInterface: fmt::Debug { + /// Checks if the wifi interface on host machine is enables. + fn is_wifi_enabled() -> bool; + + /// Turns on the wifi interface of host machine. + fn turn_on() -> Result; + + // Turns off the wifi interface of host machine. + fn turn_off() -> Result; +} diff --git a/src/platforms/osx.rs b/src/platforms/osx.rs new file mode 100644 index 0000000..9eef58b --- /dev/null +++ b/src/platforms/osx.rs @@ -0,0 +1,7 @@ +use std::collections::HashMap; + +#[derive(Debug)] +pub struct Osx { + hotspot: Option, + connectivity: Option, +} diff --git a/src/platforms/windows.rs b/src/platforms/windows.rs new file mode 100644 index 0000000..25c5e8d --- /dev/null +++ b/src/platforms/windows.rs @@ -0,0 +1,22 @@ +use std::collections::HashMap; +use + +#[derive(Debug)] +pub struct Windows { + hotspot: Option, + connectivity: Option, +} + +impl WifiInterface for Windows { + fn is_wifi_enabled() -> bool { + unimplemented!() + } + + fn turn_on() -> Result { + unimplemented!() + } + + fn turn_off() -> Result { + unimplemented!() + } +}