use std::{
io::{Error, ErrorKind, Result},
net::IpAddr,
};
#[cfg(not(target_os = "windows"))]
macro_rules! asserted_const_with_type {
($name:ident, $t1:ty, $e:expr, $t2:ty) => {
#[allow(
clippy::allow_attributes,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
reason = "Guarded by the following `const_assert_eq!`."
)]
const $name: $t1 = $e as $t1;
const_assert_eq!($name as $t2, $e);
};
}
#[cfg(any(target_os = "macos", bsd))]
mod bsd;
#[cfg(any(target_os = "linux", target_os = "android"))]
mod linux;
#[cfg(target_os = "windows")]
mod windows;
#[cfg(not(target_os = "windows"))]
mod routesocket;
#[cfg(any(target_os = "macos", bsd))]
use bsd::interface_and_mtu_impl;
#[cfg(any(target_os = "linux", target_os = "android"))]
use linux::interface_and_mtu_impl;
#[cfg(target_os = "windows")]
use windows::interface_and_mtu_impl;
fn default_err() -> Error {
Error::new(ErrorKind::NotFound, "Local interface MTU not found")
}
#[cfg(not(target_os = "windows"))]
fn unlikely_err(msg: String) -> Error {
debug_assert!(false, "{msg}");
Error::other(msg)
}
#[cfg(not(target_os = "windows"))]
const fn aligned_by(size: usize, align: usize) -> usize {
if size == 0 {
align
} else {
1 + ((size - 1) | (align - 1))
}
}
#[cfg(any(target_os = "ios", target_os = "tvos", target_os = "visionos"))]
pub fn interface_and_mtu_impl(remote: IpAddr) -> Result<(String, usize)> {
return Err(default_err());
}
pub fn interface_and_mtu(remote: IpAddr) -> Result<(String, usize)> {
interface_and_mtu_impl(remote)
}
#[cfg(test)]
mod test {
use std::{
env,
net::{IpAddr, Ipv4Addr, Ipv6Addr},
};
use crate::interface_and_mtu;
#[derive(Debug)]
struct NameMtu<'a>(Option<&'a str>, usize);
impl PartialEq<NameMtu<'_>> for (String, usize) {
fn eq(&self, other: &NameMtu<'_>) -> bool {
other.0.map_or(true, |name| name == self.0) && other.1 == self.1
}
}
const LOOPBACK: [NameMtu; 2] = if cfg!(any(target_os = "macos", target_os = "freebsd")) {
[NameMtu(Some("lo0"), 16_384), NameMtu(Some("lo0"), 16_384)]
} else if cfg!(any(target_os = "linux", target_os = "android")) {
[NameMtu(Some("lo"), 65_536), NameMtu(Some("lo"), 65_536)]
} else if cfg!(target_os = "windows") {
[
NameMtu(Some("loopback_0"), 4_294_967_295),
NameMtu(Some("loopback_0"), 4_294_967_295),
]
} else if cfg!(target_os = "openbsd") {
[NameMtu(Some("lo0"), 32_768), NameMtu(Some("lo0"), 32_768)]
} else if cfg!(target_os = "netbsd") {
[NameMtu(Some("lo0"), 33_624), NameMtu(Some("lo0"), 33_624)]
} else if cfg!(target_os = "solaris") {
[NameMtu(Some("lo0"), 8_232), NameMtu(Some("lo0"), 8_252)]
} else {
unreachable!();
};
const INET: NameMtu = NameMtu(
None,
if cfg!(target_os = "android") {
1_440 } else {
1_500
},
);
#[test]
fn loopback_v4() {
assert_eq!(
interface_and_mtu(IpAddr::V4(Ipv4Addr::LOCALHOST)).unwrap(),
LOOPBACK[0]
);
}
#[test]
fn loopback_v6() {
assert_eq!(
interface_and_mtu(IpAddr::V6(Ipv6Addr::LOCALHOST)).unwrap(),
LOOPBACK[1]
);
}
#[test]
fn inet_v4() {
assert_eq!(
interface_and_mtu(IpAddr::V4(Ipv4Addr::new(
104, 16, 132, 229 )))
.unwrap(),
INET
);
}
#[test]
fn inet_v6() {
match interface_and_mtu(IpAddr::V6(Ipv6Addr::new(
0x2606, 0x4700, 0, 0, 0, 0, 0x6810, 0x84e5, ))) {
Ok(res) => assert_eq!(res, INET),
Err(_) => assert!(env::var("GITHUB_ACTIONS").is_ok()),
}
}
}