Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ objc2-core-foundation = "0.3"
objc2-system-configuration = { version = "0.3", features = ["SCNetworkConfiguration"] }
plist = "1.8"

[target.'cfg(target_os = "macos")'.dependencies]
objc2-core-wlan = { version = "0.3" }
objc2-foundation = { version = "0.3" }

[target.'cfg(target_os = "ios")'.dependencies]
dispatch2 = "0.3"
block2 = "0.6"
Expand Down
1 change: 1 addition & 0 deletions examples/default_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ fn main() {
println!("\tIPv6: {:?}", interface.ipv6);
println!("\tTransmit Speed: {:?}", interface.transmit_speed);
println!("\tReceive Speed: {:?}", interface.receive_speed);
println!("\tAuto-negotiate: {:?}", interface.auto_negotiate);
println!("\tStats: {:?}", interface.stats);
if let Some(gateway) = interface.gateway {
println!("Default Gateway");
Expand Down
1 change: 1 addition & 0 deletions examples/list_interfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ fn main() {

println!("\tTransmit Speed: {:?}", interface.transmit_speed);
println!("\tReceive Speed: {:?}", interface.receive_speed);
println!("\tAuto-negotiate: {:?}", interface.auto_negotiate);
println!("\tStats: {:?}", interface.stats);
#[cfg(feature = "gateway")]
if let Some(gateway) = interface.gateway {
Expand Down
7 changes: 6 additions & 1 deletion src/interface/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,18 @@ pub struct Interface {
pub oper_state: OperState,
/// Transmit link speed in bits per second.
///
/// This field is usually available on Linux, Android, and Windows.
/// This field is usually available on Linux, Android, BSD, macOS and Windows.
/// It may be `None` for virtual adapters, unsupported drivers, or platforms that do not
/// expose link speed.
pub transmit_speed: Option<u64>,
/// Reported receive link speed in bits per second.
///
/// This field follows the same availability rules as `Interface::transmit_speed`.
pub receive_speed: Option<u64>,
/// Whether this interface was configured to auto-negotiate the link speed.
///
/// It may `None` if reading this information has not been implemented for a specific OS.
pub auto_negotiate: Option<bool>,
/// Traffic counters captured when the interface snapshot was collected.
///
/// The counters are cumulative totals reported by the OS, typically since boot.
Expand Down Expand Up @@ -133,6 +137,7 @@ impl Interface {
oper_state: OperState::Unknown,
transmit_speed: None,
receive_speed: None,
auto_negotiate: None,
stats: None,
#[cfg(feature = "gateway")]
gateway: None,
Expand Down
1 change: 1 addition & 0 deletions src/os/android/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ pub fn interfaces() -> Vec<Interface> {
oper_state: OperState::from_if_flags(r.flags),
transmit_speed: None,
receive_speed: None,
auto_negotiate: None,
stats: r.stats.clone(),
#[cfg(feature = "gateway")]
gateway: None,
Expand Down
1 change: 1 addition & 0 deletions src/os/linux/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub fn interfaces() -> Vec<Interface> {
oper_state: OperState::from_if_flags(r.flags),
transmit_speed: None,
receive_speed: None,
auto_negotiate: None,
stats: None,
#[cfg(feature = "gateway")]
gateway: None,
Expand Down
18 changes: 12 additions & 6 deletions src/os/macos/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@ use crate::os::darwin::types::{get_functional_type, interface_type_by_name};
use crate::os::macos::sc::{get_sc_interface_map, read_sc_interfaces_plist_map};
use crate::{
interface::interface::Interface,
os::{macos::sc::SCInterface, unix::interface::unix_interfaces},
os::{
macos::sc::SCInterface, macos::wifi::get_wifi_transmit_rate,
unix::interface::unix_interfaces,
},
prelude::InterfaceType,
};

use std::collections::HashMap;

pub fn interfaces() -> Vec<Interface> {
let mut ifaces: Vec<Interface> = unix_interfaces();

let if_extra_map: HashMap<String, SCInterface> = match read_sc_interfaces_plist_map() {
Ok(m) => m,
Err(_) => {
let if_extra_map: HashMap<String, SCInterface> =
read_sc_interfaces_plist_map().unwrap_or_else(|_| {
// Fallback to SCNetworkInterfaceCopyAll ...
get_sc_interface_map()
}
};
});

#[cfg(feature = "gateway")]
let gateway_map = crate::os::darwin::route::get_gateway_map();
Expand All @@ -40,6 +42,10 @@ pub fn interfaces() -> Vec<Interface> {
iface.friendly_name = sc_inface.friendly_name.clone();
}

if iface.if_type == InterfaceType::Wireless80211 {
iface.transmit_speed = get_wifi_transmit_rate(&iface.name);
}

#[cfg(feature = "gateway")]
{
if let Some(gateway) = gateway_map.get(&iface.index) {
Expand Down
2 changes: 2 additions & 0 deletions src/os/macos/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
pub mod interface;
pub mod sc;

mod wifi;
14 changes: 14 additions & 0 deletions src/os/macos/wifi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use objc2_core_wlan::CWWiFiClient;
use objc2_foundation::NSString;

/// Returns the macOS Wi-Fi transmit rate in bps for the given interface name.
pub(crate) fn get_wifi_transmit_rate(iface_name: &str) -> Option<u64> {
let client = unsafe { CWWiFiClient::sharedWiFiClient() };
let name = NSString::from_str(iface_name);

let wifi_iface = unsafe { client.interfaceWithName(Some(&name)) };
wifi_iface.map(|i| {
let transmit_rate = unsafe { i.transmitRate() };
return (transmit_rate * 1e6) as u64;
})
}
15 changes: 15 additions & 0 deletions src/os/unix/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ fn unix_interfaces_inner(
Some(ipv6_addr) => vec![get_ipv6_addr_flags(&name, &ipv6_addr.addr())],
None => Vec::new(),
};

let interface: Interface = Interface {
index: if_index,
name,
Expand All @@ -163,6 +164,7 @@ fn unix_interfaces_inner(
oper_state: OperState::from_if_flags(addr_ref.ifa_flags),
transmit_speed: None,
receive_speed: None,
auto_negotiate: None,
stats,
#[cfg(feature = "gateway")]
gateway: None,
Expand All @@ -183,6 +185,19 @@ fn unix_interfaces_inner(
if iface.index == 0 {
iface.index = if_nametoindex_or_zero(&iface.name);
}

#[cfg(any(
target_os = "macos",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd"
))]
if let Some(ls) = crate::os::unix::link_speed::get_link_speed(&iface.name).ok() {
iface.transmit_speed = ls.bps;
iface.receive_speed = ls.bps;

iface.auto_negotiate = Some(ls.auto_negotiate);
}
}
ifaces
}
Expand Down
Loading
Loading