From 8ec260c210f3c9e86e046cba74f9d0ebc26be3b4 Mon Sep 17 00:00:00 2001 From: SebasF <33849340+SebasF1349@users.noreply.github.com> Date: Tue, 8 Oct 2024 23:56:40 -0300 Subject: [PATCH 1/2] fix: network data using winapi --- packages/desktop/Cargo.toml | 2 +- .../src/providers/network/wifi_hotspot.rs | 115 ++++++++++++------ 2 files changed, 79 insertions(+), 38 deletions(-) diff --git a/packages/desktop/Cargo.toml b/packages/desktop/Cargo.toml index 938e89fe..3fd1a879 100644 --- a/packages/desktop/Cargo.toml +++ b/packages/desktop/Cargo.toml @@ -43,10 +43,10 @@ windows = { version = "0.58", features = [ "Win32_Globalization", "Win32_System_Console", "Win32_System_SystemServices", - "Win32_System_Threading", "Win32_UI_WindowsAndMessaging", "Win32_UI_Input_KeyboardAndMouse", "Win32_UI_TextServices", + "Win32_NetworkManagement_WiFi", ] } [target.'cfg(target_os = "macos")'.dependencies] diff --git a/packages/desktop/src/providers/network/wifi_hotspot.rs b/packages/desktop/src/providers/network/wifi_hotspot.rs index 05307557..318b1fa7 100644 --- a/packages/desktop/src/providers/network/wifi_hotspot.rs +++ b/packages/desktop/src/providers/network/wifi_hotspot.rs @@ -1,11 +1,15 @@ -#[cfg(target_os = "windows")] -use std::os::windows::process::CommandExt; -use std::process::Command; +use std::ffi::c_void; use anyhow::Context; -use regex::Regex; #[cfg(target_os = "windows")] -use windows::Win32::System::Threading::CREATE_NO_WINDOW; +use windows::Win32::{ + Foundation::{HANDLE, INVALID_HANDLE_VALUE, WIN32_ERROR}, + NetworkManagement::WiFi::{ + wlan_intf_opcode_current_connection, WlanCloseHandle, + WlanEnumInterfaces, WlanFreeMemory, WlanOpenHandle, + WlanQueryInterface, WLAN_CONNECTION_ATTRIBUTES, + }, +}; #[derive(Debug)] pub struct WifiHotstop { @@ -13,11 +17,18 @@ pub struct WifiHotstop { pub signal_strength: Option, } -/// Runs the netsh command and parses the output to get the primary -/// interface's SSID and signal strength. -// -/// Unclear if the primary interface is always the default interface -/// returned by the netdev/defaultnet crate - requires more testing. +#[derive(Debug)] +struct WlanHandle(HANDLE); + +impl Drop for WlanHandle { + fn drop(&mut self) { + unsafe { + WlanCloseHandle(self.0, None); + } + } +} + +/// Gets wifi ssid and signal stregth using winapi pub fn default_gateway_wifi() -> anyhow::Result { #[cfg(not(target_os = "windows"))] { @@ -28,42 +39,72 @@ pub fn default_gateway_wifi() -> anyhow::Result { } #[cfg(target_os = "windows")] { - let ssid_match = Regex::new(r"(?m)^\s*SSID\s*:\s*(.*?)\r?$").unwrap(); + let mut pdw_negotiated_version = 0; + let mut wlan_handle = WlanHandle(INVALID_HANDLE_VALUE); - let signal_match = - Regex::new(r"(?m)^\s*Signal\s*:\s*(.*?)\r?$").unwrap(); + WIN32_ERROR(unsafe { + WlanOpenHandle( + 2, + None, + &mut pdw_negotiated_version, + &mut wlan_handle.0, + ) + }) + .ok() + .context("Failed to open Wlan handle")?; - let signal_strip = Regex::new(r"(\d+)%").unwrap(); + let mut wlan_interface_info_list = std::ptr::null_mut(); + WIN32_ERROR(unsafe { + WlanEnumInterfaces( + wlan_handle.0, + None, + &mut wlan_interface_info_list, + ) + }) + .ok() + .context("Failed to get Wlan interfaces")?; - let output = Command::new("netsh") - .args(&["wlan", "show", "interfaces"]) - .creation_flags(CREATE_NO_WINDOW.0) - .output() - .context("Could not run netsh.")?; + let guid = (unsafe { *wlan_interface_info_list }).InterfaceInfo[0] + .InterfaceGuid; + unsafe { WlanFreeMemory(wlan_interface_info_list as *mut c_void) }; - let output = String::from_utf8_lossy(&output.stdout); + let mut data_size = 0; + let mut pdata = std::ptr::null_mut(); + + WIN32_ERROR(unsafe { + WlanQueryInterface( + wlan_handle.0, + &guid, + wlan_intf_opcode_current_connection, + None, + &mut data_size, + &mut pdata, + None, + ) + }) + .ok() + .context("Failed to get connected Wlan interface")?; - let ssid = ssid_match - .captures(&output) - .context("Failed to parse WiFi hotspot SSID.")? - .get(1) - .map(|s| s.as_str().to_string()); + let wlan_connection_atributes = + pdata as *mut WLAN_CONNECTION_ATTRIBUTES; + let atributes = + unsafe { *wlan_connection_atributes }.wlanAssociationAttributes; - let signal_str = signal_match - .captures(&output) - .context("Failed to parse WiFi hotspot signal strength.")? - .get(1) - .map(|s| s.as_str()); + unsafe { WlanFreeMemory(pdata) }; - let signal = signal_str - .and_then(|s| signal_strip.captures(s)) - .context("Failed to parse WiFi hotspot signal strength.")? - .get(1) - .and_then(|s| s.as_str().parse().ok()); + // needed to remove leading zeros in array + let ssid_arr = atributes.dot11Ssid.ucSSID; + let mut ssid_vec = ssid_arr + .into_iter() + .rev() + .skip_while(|&byte| byte == 0) + .collect::>(); + ssid_vec.reverse(); + let ssid = String::from_utf8(ssid_vec).unwrap(); Ok(WifiHotstop { - ssid, - signal_strength: signal, + ssid: Some(ssid), + signal_strength: Some(atributes.wlanSignalQuality), }) } } From 5d1e24b9418abc35d2d24454940ca0bd2df1f34c Mon Sep 17 00:00:00 2001 From: SebasF <33849340+SebasF1349@users.noreply.github.com> Date: Fri, 11 Oct 2024 00:35:42 -0300 Subject: [PATCH 2/2] fix: added missing cfg + error handling --- packages/desktop/src/providers/network/wifi_hotspot.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/desktop/src/providers/network/wifi_hotspot.rs b/packages/desktop/src/providers/network/wifi_hotspot.rs index 318b1fa7..a6df4ddf 100644 --- a/packages/desktop/src/providers/network/wifi_hotspot.rs +++ b/packages/desktop/src/providers/network/wifi_hotspot.rs @@ -18,8 +18,10 @@ pub struct WifiHotstop { } #[derive(Debug)] +#[cfg(target_os = "windows")] struct WlanHandle(HANDLE); +#[cfg(target_os = "windows")] impl Drop for WlanHandle { fn drop(&mut self) { unsafe { @@ -28,7 +30,7 @@ impl Drop for WlanHandle { } } -/// Gets wifi ssid and signal stregth using winapi +/// Gets wifi ssid and signal strength using winapi pub fn default_gateway_wifi() -> anyhow::Result { #[cfg(not(target_os = "windows"))] { @@ -100,7 +102,8 @@ pub fn default_gateway_wifi() -> anyhow::Result { .skip_while(|&byte| byte == 0) .collect::>(); ssid_vec.reverse(); - let ssid = String::from_utf8(ssid_vec).unwrap(); + let ssid = + String::from_utf8(ssid_vec).context("Incorrectly formatted ssid")?; Ok(WifiHotstop { ssid: Some(ssid),