windows upnp work

This commit is contained in:
John Smith 2023-10-13 17:57:38 -04:00
parent ebd36d82ef
commit d922bc1f5d
20 changed files with 138 additions and 111 deletions

16
Cargo.lock generated
View File

@ -499,14 +499,13 @@ checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3"
[[package]] [[package]]
name = "attohttpc" name = "attohttpc"
version = "0.16.3" version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb8867f378f33f78a811a8eb9bf108ad99430d7aad43315dd9319c827ef6247" checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2"
dependencies = [ dependencies = [
"http", "http",
"log", "log",
"url", "url",
"wildmatch",
] ]
[[package]] [[package]]
@ -5406,9 +5405,9 @@ dependencies = [
[[package]] [[package]]
name = "veilid-igd" name = "veilid-igd"
version = "0.1.0" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28428a3f826ed334f995522e554d7c8c1a5a0e0a0248fc795a31022ddf436c9d" checksum = "ce2b3c073da0025538ff4cf5bea61a7a7a046c1bf060e2d0981c71800747551d"
dependencies = [ dependencies = [
"attohttpc", "attohttpc",
"log", "log",
@ -5517,6 +5516,7 @@ dependencies = [
"wasm-bindgen-test", "wasm-bindgen-test",
"wasm-logger", "wasm-logger",
"wee_alloc", "wee_alloc",
"winapi",
] ]
[[package]] [[package]]
@ -5781,12 +5781,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
[[package]]
name = "wildmatch"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f44b95f62d34113cf558c93511ac93027e03e9c29a60dd0fd70e6e025c7270a"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"

View File

@ -18,6 +18,7 @@ cursive_core = { git = "https://gitlab.com/veilid/cursive.git" }
# keyvaluedb-memorydb = { path = "../keyvaluedb/keyvaluedb-memorydb" } # keyvaluedb-memorydb = { path = "../keyvaluedb/keyvaluedb-memorydb" }
# keyvaluedb-sqlite = { path = "../keyvaluedb/keyvaluedb-sqlite" } # keyvaluedb-sqlite = { path = "../keyvaluedb/keyvaluedb-sqlite" }
# keyvaluedb-web = { path = "../keyvaluedb/keyvaluedb-web" } # keyvaluedb-web = { path = "../keyvaluedb/keyvaluedb-web" }
# igd = { package = "veilid-igd", path = "../rust-igd" }
[profile.release] [profile.release]
opt-level = "s" opt-level = "s"

View File

@ -170,7 +170,7 @@ keyvaluedb-sqlite = "0.1.1"
# Network # Network
async-tungstenite = { version = "0.23.0", features = ["async-tls"] } async-tungstenite = { version = "0.23.0", features = ["async-tls"] }
igd = { package = "veilid-igd", version = "0.1.0" } igd = { package = "veilid-igd", version = "0.1.1" }
async-tls = "0.12.0" async-tls = "0.12.0"
webpki = "0.22.1" webpki = "0.22.1"
webpki-roots = "0.25.2" webpki-roots = "0.25.2"

View File

@ -12,6 +12,5 @@ pub use system::*;
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
pub mod android; pub mod android;
pub mod network_interfaces;
use super::*; use super::*;

View File

@ -26,7 +26,7 @@ struct PortMapValue {
struct IGDManagerInner { struct IGDManagerInner {
local_ip_addrs: BTreeMap<AddressType, IpAddr>, local_ip_addrs: BTreeMap<AddressType, IpAddr>,
gateways: BTreeMap<AddressType, Arc<Gateway>>, gateways: BTreeMap<IpAddr, Arc<Gateway>>,
port_maps: BTreeMap<PortMapKey, PortMapValue>, port_maps: BTreeMap<PortMapKey, PortMapValue>,
} }
@ -121,17 +121,21 @@ impl IGDManager {
fn find_gateway( fn find_gateway(
inner: &mut IGDManagerInner, inner: &mut IGDManagerInner,
address_type: AddressType, local_ip: IpAddr,
) -> Option<Arc<Gateway>> { ) -> Option<Arc<Gateway>> {
if let Some(gw) = inner.gateways.get(&address_type) {
if let Some(gw) = inner.gateways.get(&local_ip) {
return Some(gw.clone()); return Some(gw.clone());
} }
let gateway = match address_type { let gateway = match local_ip {
AddressType::IPV4 => { IpAddr::V4(v4) => {
match igd::search_gateway(SearchOptions::new_v4( let mut opts = SearchOptions::new_v4(
UPNP_GATEWAY_DETECT_TIMEOUT_MS as u64, UPNP_GATEWAY_DETECT_TIMEOUT_MS as u64,
)) { );
opts.bind_addr = SocketAddr::V4(SocketAddrV4::new(v4, 0));
match igd::search_gateway(opts) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
log_net!(debug "couldn't find ipv4 igd: {}", e); log_net!(debug "couldn't find ipv4 igd: {}", e);
@ -139,11 +143,14 @@ impl IGDManager {
} }
} }
} }
AddressType::IPV6 => { IpAddr::V6(v6) => {
match igd::search_gateway(SearchOptions::new_v6( let mut opts = SearchOptions::new_v6(
Ipv6SearchScope::LinkLocal, Ipv6SearchScope::LinkLocal,
UPNP_GATEWAY_DETECT_TIMEOUT_MS as u64, UPNP_GATEWAY_DETECT_TIMEOUT_MS as u64,
)) { );
opts.bind_addr = SocketAddr::V6(SocketAddrV6::new(v6, 0, 0, 0));
match igd::search_gateway(opts) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
log_net!(debug "couldn't find ipv6 igd: {}", e); log_net!(debug "couldn't find ipv6 igd: {}", e);
@ -151,17 +158,18 @@ impl IGDManager {
} }
} }
} }
}; };
let gw = Arc::new(gateway); let gw = Arc::new(gateway);
inner.gateways.insert(address_type, gw.clone()); inner.gateways.insert(local_ip, gw.clone());
Some(gw) Some(gw)
} }
fn get_gateway( fn get_gateway(
inner: &mut IGDManagerInner, inner: &mut IGDManagerInner,
address_type: AddressType, local_ip: IpAddr,
) -> Option<Arc<Gateway>> { ) -> Option<Arc<Gateway>> {
if let Some(gw) = inner.gateways.get(&address_type) { if let Some(gw) = inner.gateways.get(&local_ip) {
return Some(gw.clone()); return Some(gw.clone());
} }
None None
@ -191,8 +199,12 @@ impl IGDManager {
let pmk = found?; let pmk = found?;
let _pmv = inner.port_maps.remove(&pmk).expect("key found but remove failed"); let _pmv = inner.port_maps.remove(&pmk).expect("key found but remove failed");
// Get local ip address
let local_ip = Self::find_local_ip(&mut inner, at)?;
// Find gateway // Find gateway
let gw = Self::find_gateway(&mut inner, at)?; let gw = Self::find_gateway(&mut inner, local_ip)?;
// Unmap port // Unmap port
match gw.remove_port(convert_llpt(llpt), mapped_port) { match gw.remove_port(convert_llpt(llpt), mapped_port) {
@ -233,7 +245,7 @@ impl IGDManager {
let local_ip = Self::find_local_ip(&mut inner, at)?; let local_ip = Self::find_local_ip(&mut inner, at)?;
// Find gateway // Find gateway
let gw = Self::find_gateway(&mut inner, at)?; let gw = Self::find_gateway(&mut inner, local_ip)?;
// Get external address // Get external address
let ext_ip = match gw.get_external_ip() { let ext_ip = match gw.get_external_ip() {
@ -326,14 +338,6 @@ impl IGDManager {
// Process full renewals // Process full renewals
for (k, v) in full_renews { for (k, v) in full_renews {
// Get gateway for address type
let gw = match Self::get_gateway(&mut inner, k.at) {
Some(gw) => gw,
None => {
return Err(eyre!("gateway missing for address type"));
}
};
// Get local ip for address type // Get local ip for address type
let local_ip = match Self::get_local_ip(&mut inner, k.at) { let local_ip = match Self::get_local_ip(&mut inner, k.at) {
Some(ip) => ip, Some(ip) => ip,
@ -342,6 +346,14 @@ impl IGDManager {
} }
}; };
// Get gateway for interface
let gw = match Self::get_gateway(&mut inner, local_ip) {
Some(gw) => gw,
None => {
return Err(eyre!("gateway missing for interface"));
}
};
// Delete the mapping if it exists, ignore any errors here // Delete the mapping if it exists, ignore any errors here
let _ = gw.remove_port(convert_llpt(k.llpt), v.mapped_port); let _ = gw.remove_port(convert_llpt(k.llpt), v.mapped_port);
inner.port_maps.remove(&k); inner.port_maps.remove(&k);
@ -370,14 +382,6 @@ impl IGDManager {
// Process normal renewals // Process normal renewals
for (k, mut v) in renews { for (k, mut v) in renews {
// Get gateway for address type
let gw = match Self::get_gateway(&mut inner, k.at) {
Some(gw) => gw,
None => {
return Err(eyre!("gateway missing for address type"));
}
};
// Get local ip for address type // Get local ip for address type
let local_ip = match Self::get_local_ip(&mut inner, k.at) { let local_ip = match Self::get_local_ip(&mut inner, k.at) {
Some(ip) => ip, Some(ip) => ip,
@ -386,6 +390,14 @@ impl IGDManager {
} }
}; };
// Get gateway for interface
let gw = match Self::get_gateway(&mut inner, local_ip) {
Some(gw) => gw,
None => {
return Err(eyre!("gateway missing for address type"));
}
};
let desc = this.get_description(k.llpt, k.local_port); let desc = this.get_description(k.llpt, k.local_port);
match gw.add_port(convert_llpt(k.llpt), v.mapped_port, SocketAddr::new(local_ip, k.local_port), (UPNP_MAPPING_LIFETIME_MS + 999) / 1000, &desc) { match gw.add_port(convert_llpt(k.llpt), v.mapped_port, SocketAddr::new(local_ip, k.local_port), (UPNP_MAPPING_LIFETIME_MS + 999) / 1000, &desc) {
Ok(()) => { Ok(()) => {

View File

@ -10,7 +10,6 @@ use super::*;
use crate::routing_table::*; use crate::routing_table::*;
use connection_manager::*; use connection_manager::*;
use discovery_context::*; use discovery_context::*;
use network_interfaces::*;
use network_tcp::*; use network_tcp::*;
use protocol::tcp::RawTcpProtocolHandler; use protocol::tcp::RawTcpProtocolHandler;
use protocol::udp::RawUdpProtocolHandler; use protocol::udp::RawUdpProtocolHandler;
@ -316,7 +315,7 @@ impl Network {
if !from.ip().is_unspecified() { if !from.ip().is_unspecified() {
vec![*from] vec![*from]
} else { } else {
let addrs = self.get_usable_interface_addresses(); let addrs = self.get_stable_interface_addresses();
addrs addrs
.iter() .iter()
.filter_map(|a| { .filter_map(|a| {
@ -358,13 +357,13 @@ impl Network {
}) })
} }
pub fn is_usable_interface_address(&self, addr: IpAddr) -> bool { pub fn is_stable_interface_address(&self, addr: IpAddr) -> bool {
let usable_addrs = self.get_usable_interface_addresses(); let stable_addrs = self.get_stable_interface_addresses();
usable_addrs.contains(&addr) stable_addrs.contains(&addr)
} }
pub fn get_usable_interface_addresses(&self) -> Vec<IpAddr> { pub fn get_stable_interface_addresses(&self) -> Vec<IpAddr> {
let addrs = self.unlocked_inner.interfaces.best_addresses(); let addrs = self.unlocked_inner.interfaces.stable_addresses();
let addrs: Vec<IpAddr> = addrs let addrs: Vec<IpAddr> = addrs
.into_iter() .into_iter()
.filter(|addr| { .filter(|addr| {
@ -377,7 +376,13 @@ impl Network {
// See if our interface addresses have changed, if so redo public dial info if necessary // See if our interface addresses have changed, if so redo public dial info if necessary
async fn check_interface_addresses(&self) -> EyreResult<bool> { async fn check_interface_addresses(&self) -> EyreResult<bool> {
if !self.unlocked_inner.interfaces.refresh().await? { if !self
.unlocked_inner
.interfaces
.refresh()
.await
.wrap_err("failed to check network interfaces")?
{
return Ok(false); return Ok(false);
} }
@ -723,7 +728,7 @@ impl Network {
{ {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
inner.enable_ipv4 = false; inner.enable_ipv4 = false;
for addr in self.get_usable_interface_addresses() { for addr in self.get_stable_interface_addresses() {
if addr.is_ipv4() { if addr.is_ipv4() {
log_net!(debug "enable address {:?} as ipv4", addr); log_net!(debug "enable address {:?} as ipv4", addr);
inner.enable_ipv4 = true; inner.enable_ipv4 = true;

View File

@ -342,7 +342,7 @@ impl Network {
// See if this public address is also a local interface address we haven't registered yet // See if this public address is also a local interface address we haven't registered yet
let is_interface_address = (|| { let is_interface_address = (|| {
for ip_addr in self.get_usable_interface_addresses() { for ip_addr in self.get_stable_interface_addresses() {
if pdi_addr.ip() == ip_addr { if pdi_addr.ip() == ip_addr {
return true; return true;
} }
@ -438,7 +438,7 @@ impl Network {
// See if this public address is also a local interface address // See if this public address is also a local interface address
if !registered_addresses.contains(&gsa.ip()) if !registered_addresses.contains(&gsa.ip())
&& self.is_usable_interface_address(gsa.ip()) && self.is_stable_interface_address(gsa.ip())
{ {
editor_local_network.register_dial_info(pdi, DialInfoClass::Direct)?; editor_local_network.register_dial_info(pdi, DialInfoClass::Direct)?;
} }
@ -552,7 +552,7 @@ impl Network {
// See if this public address is also a local interface address // See if this public address is also a local interface address
if !registered_addresses.contains(&gsa.ip()) if !registered_addresses.contains(&gsa.ip())
&& self.is_usable_interface_address(gsa.ip()) && self.is_stable_interface_address(gsa.ip())
{ {
editor_local_network.register_dial_info(pdi, DialInfoClass::Direct)?; editor_local_network.register_dial_info(pdi, DialInfoClass::Direct)?;
} }
@ -653,7 +653,7 @@ impl Network {
} }
// See if this public address is also a local interface address // See if this public address is also a local interface address
if self.is_usable_interface_address(pdi_addr.ip()) { if self.is_stable_interface_address(pdi_addr.ip()) {
editor_local_network.register_dial_info(pdi, DialInfoClass::Direct)?; editor_local_network.register_dial_info(pdi, DialInfoClass::Direct)?;
} }
} }

View File

@ -425,11 +425,11 @@ impl Network {
trace!("network stopped"); trace!("network stopped");
} }
pub fn is_usable_interface_address(&self, _addr: IpAddr) -> bool { pub fn is_stable_interface_address(&self, _addr: IpAddr) -> bool {
false false
} }
pub fn get_usable_interface_addresses(&self) -> Vec<IpAddr> { pub fn get_stable_interface_addresses(&self) -> Vec<IpAddr> {
Vec::new() Vec::new()
} }

View File

@ -1,4 +1,3 @@
pub mod test_host_interface;
pub mod test_protected_store; pub mod test_protected_store;
pub mod test_veilid_config; pub mod test_veilid_config;
pub mod test_veilid_core; pub mod test_veilid_core;

View File

@ -13,8 +13,6 @@ use crate::*;
#[allow(dead_code)] #[allow(dead_code)]
pub async fn run_all_tests() { pub async fn run_all_tests() {
// iOS and Android tests also run these. // iOS and Android tests also run these.
info!("TEST: test_host_interface");
test_host_interface::test_all().await;
info!("TEST: test_types"); info!("TEST: test_types");
test_types::test_all().await; test_types::test_all().await;
info!("TEST: test_veilid_core"); info!("TEST: test_veilid_core");
@ -114,8 +112,6 @@ cfg_if! {
}); });
} }
run_test!(test_host_interface);
run_test!(test_types); run_test!(test_types);
run_test!(test_veilid_core); run_test!(test_veilid_core);

View File

@ -69,7 +69,7 @@ futures-util = { version = "0.3.28", default-features = false, features = [
chrono = "0.4.31" chrono = "0.4.31"
libc = "0.2.148" libc = "0.2.148"
nix = { version = "0.27.1", features = [ "user" ] } nix = { version = "0.27.1", features = ["user"] }
# Dependencies for WASM builds only # Dependencies for WASM builds only
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
@ -93,9 +93,8 @@ paranoid-android = { version = "0.2.1", optional = true }
android_logger = "0.13.3" android_logger = "0.13.3"
# Dependencies for Windows # Dependencies for Windows
# [target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
# windows = { version = "^0", features = [ "Win32_NetworkManagement_Dns", "Win32_Foundation", "alloc" ]} winapi = { version = "0.3.9", features = ["iptypes", "iphlpapi"] }
# windows-permissions = "^0"
# Dependencies for iOS # Dependencies for iOS
[target.'cfg(target_os = "ios")'.dependencies] [target.'cfg(target_os = "ios")'.dependencies]

View File

@ -40,6 +40,7 @@ pub mod log_thru;
pub mod must_join_handle; pub mod must_join_handle;
pub mod must_join_single_future; pub mod must_join_single_future;
pub mod mutable_future; pub mod mutable_future;
pub mod network_interfaces;
pub mod network_result; pub mod network_result;
pub mod random; pub mod random;
pub mod single_shot_eventual; pub mod single_shot_eventual;
@ -182,6 +183,8 @@ pub use must_join_single_future::*;
#[doc(inline)] #[doc(inline)]
pub use mutable_future::*; pub use mutable_future::*;
#[doc(inline)] #[doc(inline)]
pub use network_interfaces::*;
#[doc(inline)]
pub use network_result::*; pub use network_result::*;
#[doc(inline)] #[doc(inline)]
pub use random::*; pub use random::*;

View File

@ -1,3 +1,4 @@
#![cfg(any(target_os = "macos", target_os = "ios"))]
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use super::*; use super::*;
@ -273,10 +274,10 @@ pub struct PlatformSupportApple {
} }
impl PlatformSupportApple { impl PlatformSupportApple {
pub fn new() -> EyreResult<Self> { pub fn new() -> Self {
Ok(PlatformSupportApple { PlatformSupportApple {
default_route_interfaces: BTreeSet::new(), default_route_interfaces: BTreeSet::new(),
}) }
} }
async fn refresh_default_route_interfaces(&mut self) -> EyreResult<()> { async fn refresh_default_route_interfaces(&mut self) -> EyreResult<()> {
@ -433,11 +434,11 @@ impl PlatformSupportApple {
pub async fn get_interfaces( pub async fn get_interfaces(
&mut self, &mut self,
interfaces: &mut BTreeMap<String, NetworkInterface>, interfaces: &mut BTreeMap<String, NetworkInterface>,
) -> EyreResult<()> { ) -> io::Result<()> {
self.refresh_default_route_interfaces().await?; self.refresh_default_route_interfaces().await?;
// Ask for all the addresses we have // Ask for all the addresses we have
let ifaddrs = IfAddrs::new().wrap_err("failed to get interface addresses")?; let ifaddrs = IfAddrs::new()?;
for ifaddr in ifaddrs.iter() { for ifaddr in ifaddrs.iter() {
// Get the interface name // Get the interface name
let ifname = unsafe { CStr::from_ptr(ifaddr.ifa_name) } let ifname = unsafe { CStr::from_ptr(ifaddr.ifa_name) }

View File

@ -1,18 +1,17 @@
mod apple;
mod netlink;
mod sockaddr_tools;
mod tools; mod tools;
mod windows;
use crate::*; use crate::*;
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "android"))] { if #[cfg(any(target_os = "linux", target_os = "android"))] {
mod netlink;
use self::netlink::PlatformSupportNetlink as PlatformSupport; use self::netlink::PlatformSupportNetlink as PlatformSupport;
} else if #[cfg(target_os = "windows")] { } else if #[cfg(target_os = "windows")] {
mod windows;
mod sockaddr_tools;
use self::windows::PlatformSupportWindows as PlatformSupport; use self::windows::PlatformSupportWindows as PlatformSupport;
} else if #[cfg(any(target_os = "macos", target_os = "ios"))] { } else if #[cfg(any(target_os = "macos", target_os = "ios"))] {
mod apple;
mod sockaddr_tools;
use self::apple::PlatformSupportApple as PlatformSupport; use self::apple::PlatformSupportApple as PlatformSupport;
} else { } else {
compile_error!("No network interfaces support for this platform!"); compile_error!("No network interfaces support for this platform!");
@ -315,13 +314,22 @@ impl fmt::Debug for NetworkInterfaces {
.finish()?; .finish()?;
if f.alternate() { if f.alternate() {
writeln!(f)?; writeln!(f)?;
writeln!(f, "// best_addresses: {:?}", inner.interface_address_cache)?; writeln!(
f,
"// stable_addresses: {:?}",
inner.interface_address_cache
)?;
} }
Ok(()) Ok(())
} }
} }
#[allow(dead_code)] impl Default for NetworkInterfaces {
fn default() -> Self {
Self::new()
}
}
impl NetworkInterfaces { impl NetworkInterfaces {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -344,14 +352,14 @@ impl NetworkInterfaces {
inner.interface_address_cache.clear(); inner.interface_address_cache.clear();
inner.valid = false; inner.valid = false;
} }
// returns Ok(false) if refresh had no changes, Ok(true) if changes were present // returns false if refresh had no changes, true if changes were present
pub async fn refresh(&self) -> EyreResult<bool> { pub async fn refresh(&self) -> std::io::Result<bool> {
let mut last_interfaces = { let mut last_interfaces = {
let mut last_interfaces = BTreeMap::<String, NetworkInterface>::new(); let mut last_interfaces = BTreeMap::<String, NetworkInterface>::new();
let mut platform_support = PlatformSupport::new()?; let mut platform_support = PlatformSupport::new();
if let Err(e) = platform_support.get_interfaces(&mut last_interfaces).await { platform_support
debug!("no network interfaces are enabled: {}", e); .get_interfaces(&mut last_interfaces)
} .await?;
last_interfaces last_interfaces
}; };
@ -361,16 +369,16 @@ impl NetworkInterfaces {
if last_interfaces != inner.interfaces { if last_interfaces != inner.interfaces {
// get last address cache // get last address cache
let old_best_addresses = inner.interface_address_cache.clone(); let old_stable_addresses = inner.interface_address_cache.clone();
// redo the address cache // redo the address cache
Self::cache_best_addresses(&mut inner); Self::cache_stable_addresses(&mut inner);
// See if our best addresses have changed // See if our best addresses have changed
if old_best_addresses != inner.interface_address_cache { if old_stable_addresses != inner.interface_address_cache {
debug!( debug!(
"Network interface addresses changed: \nFrom: {:?}\n To: {:?}\n", "Network interface addresses changed: \nFrom: {:?}\n To: {:?}\n",
old_best_addresses, inner.interface_address_cache old_stable_addresses, inner.interface_address_cache
); );
return Ok(true); return Ok(true);
} }
@ -385,14 +393,14 @@ impl NetworkInterfaces {
f(&inner.interfaces) f(&inner.interfaces)
} }
pub fn best_addresses(&self) -> Vec<IpAddr> { pub fn stable_addresses(&self) -> Vec<IpAddr> {
let inner = self.inner.lock(); let inner = self.inner.lock();
inner.interface_address_cache.clone() inner.interface_address_cache.clone()
} }
///////////////////////////////////////////// /////////////////////////////////////////////
fn cache_best_addresses(inner: &mut NetworkInterfacesInner) { fn cache_stable_addresses(inner: &mut NetworkInterfacesInner) {
// Reduce interfaces to their best routable ip addresses // Reduce interfaces to their best routable ip addresses
let mut intf_addrs = Vec::new(); let mut intf_addrs = Vec::new();
for intf in inner.interfaces.values() { for intf in inner.interfaces.values() {

View File

@ -1,3 +1,5 @@
#![cfg(any(target_os = "linux", target_os = "android"))]
use super::*; use super::*;
use alloc::collections::btree_map::Entry; use alloc::collections::btree_map::Entry;
@ -27,7 +29,7 @@ use std::io;
use std::os::raw::c_int; use std::os::raw::c_int;
use tools::*; use tools::*;
fn get_interface_name(index: u32) -> EyreResult<String> { fn get_interface_name(index: u32) -> io::Result<String> {
let mut ifnamebuf = [0u8; (IF_NAMESIZE + 1)]; let mut ifnamebuf = [0u8; (IF_NAMESIZE + 1)];
cfg_if! { cfg_if! {
if #[cfg(all(any(target_os = "android", target_os="linux"), any(target_arch = "arm", target_arch = "aarch64")))] { if #[cfg(all(any(target_os = "android", target_os="linux"), any(target_arch = "arm", target_arch = "aarch64")))] {
@ -69,12 +71,12 @@ pub struct PlatformSupportNetlink {
} }
impl PlatformSupportNetlink { impl PlatformSupportNetlink {
pub fn new() -> EyreResult<Self> { pub fn new() -> Self {
Ok(PlatformSupportNetlink { PlatformSupportNetlink {
connection_jh: None, connection_jh: None,
handle: None, handle: None,
default_route_interfaces: BTreeSet::new(), default_route_interfaces: BTreeSet::new(),
}) }
} }
// Figure out which interfaces have default routes // Figure out which interfaces have default routes
@ -245,18 +247,14 @@ impl PlatformSupportNetlink {
async fn get_interfaces_internal( async fn get_interfaces_internal(
&mut self, &mut self,
interfaces: &mut BTreeMap<String, NetworkInterface>, interfaces: &mut BTreeMap<String, NetworkInterface>,
) -> EyreResult<()> { ) -> io::Result<()> {
// Refresh the routes // Refresh the routes
self.refresh_default_route_interfaces().await?; self.refresh_default_route_interfaces().await?;
// Ask for all the addresses we have // Ask for all the addresses we have
let mut names = BTreeMap::<u32, String>::new(); let mut names = BTreeMap::<u32, String>::new();
let mut addresses = self.handle.as_ref().unwrap().address().get().execute(); let mut addresses = self.handle.as_ref().unwrap().address().get().execute();
while let Some(msg) = addresses while let Some(msg) = addresses.try_next().await? {
.try_next()
.await
.wrap_err("failed to iterate interface addresses")?
{
// Have we seen this interface index yet? // Have we seen this interface index yet?
// Get the name from the index, cached, if we can // Get the name from the index, cached, if we can
let ifname = match names.entry(msg.header.index) { let ifname = match names.entry(msg.header.index) {
@ -314,10 +312,9 @@ impl PlatformSupportNetlink {
pub async fn get_interfaces( pub async fn get_interfaces(
&mut self, &mut self,
interfaces: &mut BTreeMap<String, NetworkInterface>, interfaces: &mut BTreeMap<String, NetworkInterface>,
) -> EyreResult<()> { ) -> io::Result<()> {
// Get the netlink connection // Get the netlink connection
let (connection, handle, _) = new_connection_with_socket::<RTNetLinkSocket>() let (connection, handle, _) = new_connection_with_socket::<RTNetLinkSocket>()?;
.wrap_err("failed to create rtnetlink socket")?;
// Spawn a connection handler // Spawn a connection handler
let connection_jh = spawn(connection); let connection_jh = spawn(connection);

View File

@ -1,3 +1,5 @@
#![cfg(target_os = "windows")]
// Copyright 2018 MaidSafe.net limited. // Copyright 2018 MaidSafe.net limited.
// //
// This SAFE Network Software is licensed to you under the MIT license <LICENSE-MIT // This SAFE Network Software is licensed to you under the MIT license <LICENSE-MIT
@ -28,8 +30,8 @@ use winapi::um::iptypes::{
pub struct PlatformSupportWindows {} pub struct PlatformSupportWindows {}
impl PlatformSupportWindows { impl PlatformSupportWindows {
pub fn new() -> EyreResult<Self> { pub fn new() -> Self {
Ok(PlatformSupportWindows {}) PlatformSupportWindows {}
} }
fn get_interface_flags(intf: &IpAdapterAddresses) -> InterfaceFlags { fn get_interface_flags(intf: &IpAdapterAddresses) -> InterfaceFlags {
@ -55,10 +57,9 @@ impl PlatformSupportWindows {
pub async fn get_interfaces( pub async fn get_interfaces(
&mut self, &mut self,
interfaces: &mut BTreeMap<String, NetworkInterface>, interfaces: &mut BTreeMap<String, NetworkInterface>,
) -> EyreResult<()> { ) -> io::Result<()> {
// Iterate all the interfaces // Iterate all the interfaces
let windows_interfaces = let windows_interfaces = WindowsInterfaces::new()?;
WindowsInterfaces::new().wrap_err("failed to get windows interfaces")?;
for windows_interface in windows_interfaces.iter() { for windows_interface in windows_interfaces.iter() {
// Get name // Get name
let intf_name = windows_interface.name(); let intf_name = windows_interface.name();

View File

@ -3,6 +3,7 @@
mod test_assembly_buffer; mod test_assembly_buffer;
mod test_async_peek_stream; mod test_async_peek_stream;
mod test_network_interfaces;
use super::*; use super::*;
@ -13,6 +14,8 @@ use super::*;
pub async fn run_all_tests() { pub async fn run_all_tests() {
info!("TEST: exec_test_host_interface"); info!("TEST: exec_test_host_interface");
test_host_interface::test_all().await; test_host_interface::test_all().await;
info!("TEST: exec_test_network_interfaces");
test_network_interfaces::test_all().await;
info!("TEST: exec_test_async_peek_stream"); info!("TEST: exec_test_async_peek_stream");
test_async_peek_stream::test_all().await; test_async_peek_stream::test_all().await;
info!("TEST: exec_test_async_tag_lock"); info!("TEST: exec_test_async_tag_lock");
@ -82,6 +85,15 @@ cfg_if! {
}); });
} }
#[test]
#[serial]
fn run_test_network_interfaces() {
setup();
block_on(async {
test_network_interfaces::test_all().await;
});
}
#[test] #[test]
#[serial] #[serial]
fn run_test_async_peek_stream() { fn run_test_async_peek_stream() {

View File

@ -2,7 +2,7 @@ use crate::*;
cfg_if! { cfg_if! {
if #[cfg(not(target_arch = "wasm32"))] { if #[cfg(not(target_arch = "wasm32"))] {
use intf::network_interfaces::NetworkInterfaces; use network_interfaces::NetworkInterfaces;
pub async fn test_network_interfaces() { pub async fn test_network_interfaces() {
info!("testing network interfaces"); info!("testing network interfaces");