use windows::Win32::{
Networking::{
self,
NetworkListManager::{
INetworkListManager, NLM_CONNECTIVITY, NLM_CONNECTIVITY_DISCONNECTED,
NLM_CONNECTIVITY_IPV4_INTERNET, NLM_CONNECTIVITY_IPV4_LOCALNETWORK,
NLM_CONNECTIVITY_IPV4_NOTRAFFIC, NLM_CONNECTIVITY_IPV4_SUBNET,
NLM_CONNECTIVITY_IPV6_INTERNET, NLM_CONNECTIVITY_IPV6_LOCALNETWORK,
NLM_CONNECTIVITY_IPV6_NOTRAFFIC, NLM_CONNECTIVITY_IPV6_SUBNET,
},
},
System::Com::{CoCreateInstance, CLSCTX_ALL},
};
use crate::network::IpVersion;
use super::com::ComInit;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Connectivity {
Disconnected = 0,
Ipv4Notraffic = 0x1,
Ipv6Notraffic = 0x2,
Ipv4Subnet = 0x10,
Ipv4Localnetwork = 0x20,
Ipv4Internet = 0x40,
Ipv6Subnet = 0x100,
Ipv6Localnetwork = 0x200,
Ipv6Internet = 0x400,
}
impl Connectivity {
#[must_use]
pub fn get() -> Self {
Self::try_get().unwrap()
}
pub fn try_get() -> windows::core::Result<Self> {
unsafe {
let manager = get_networklist_manager()?;
get_connectivity(&manager)
}
}
#[must_use]
pub fn ip_version(&self) -> Option<IpVersion> {
match self {
Connectivity::Ipv4Internet
| Connectivity::Ipv4Localnetwork
| Connectivity::Ipv4Subnet
| Connectivity::Ipv4Notraffic => Some(IpVersion::V4),
Connectivity::Ipv6Internet
| Connectivity::Ipv6Localnetwork
| Connectivity::Ipv6Subnet
| Connectivity::Ipv6Notraffic => Some(IpVersion::V6),
Connectivity::Disconnected => None,
}
}
}
impl From<NLM_CONNECTIVITY> for Connectivity {
fn from(connectivity: NLM_CONNECTIVITY) -> Self {
match connectivity {
NLM_CONNECTIVITY_DISCONNECTED => Connectivity::Disconnected,
NLM_CONNECTIVITY_IPV4_INTERNET => Connectivity::Ipv4Internet,
NLM_CONNECTIVITY_IPV4_LOCALNETWORK => Connectivity::Ipv4Localnetwork,
NLM_CONNECTIVITY_IPV4_SUBNET => Connectivity::Ipv4Subnet,
NLM_CONNECTIVITY_IPV6_INTERNET => Connectivity::Ipv6Internet,
NLM_CONNECTIVITY_IPV6_LOCALNETWORK => Connectivity::Ipv6Localnetwork,
NLM_CONNECTIVITY_IPV6_NOTRAFFIC => Connectivity::Ipv6Notraffic,
NLM_CONNECTIVITY_IPV6_SUBNET => Connectivity::Ipv6Subnet,
_ => Connectivity::Ipv4Notraffic,
}
}
}
impl From<Connectivity> for NLM_CONNECTIVITY {
fn from(connectivity: Connectivity) -> Self {
match connectivity {
Connectivity::Disconnected => NLM_CONNECTIVITY_DISCONNECTED,
Connectivity::Ipv4Internet => NLM_CONNECTIVITY_IPV4_INTERNET,
Connectivity::Ipv4Localnetwork => NLM_CONNECTIVITY_IPV4_LOCALNETWORK,
Connectivity::Ipv4Notraffic => NLM_CONNECTIVITY_IPV4_NOTRAFFIC,
Connectivity::Ipv4Subnet => NLM_CONNECTIVITY_IPV4_SUBNET,
Connectivity::Ipv6Internet => NLM_CONNECTIVITY_IPV6_INTERNET,
Connectivity::Ipv6Localnetwork => NLM_CONNECTIVITY_IPV6_LOCALNETWORK,
Connectivity::Ipv6Notraffic => NLM_CONNECTIVITY_IPV6_NOTRAFFIC,
Connectivity::Ipv6Subnet => NLM_CONNECTIVITY_IPV6_SUBNET,
}
}
}
pub unsafe fn get_networklist_manager() -> windows::core::Result<INetworkListManager> {
ComInit::init();
CoCreateInstance(
&Networking::NetworkListManager::NetworkListManager,
None,
CLSCTX_ALL,
)
}
pub unsafe fn get_connectivity(
manager: &INetworkListManager,
) -> windows::core::Result<Connectivity> {
let conn = manager.GetConnectivity()?;
Ok(conn.into())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_manager() {
assert_eq!(unsafe { get_networklist_manager() }.err(), None);
}
}