irox-safe-windows 0.1.4

Wrappers around the windows native unsafe functions to make them ergonomic
Documentation
use crate::error::Error;
use core::slice;
use std::ffi::c_void;
use windows::Win32::NetworkManagement::IpHelper::{
    FreeMibTable, GetInterfaceActiveTimestampCapabilities, GetIpInterfaceTable,
    INTERFACE_TIMESTAMP_CAPABILITIES, MIB_IPINTERFACE_ROW, MIB_IPINTERFACE_TABLE,
};
use windows::Win32::NetworkManagement::Ndis::NET_LUID_LH;
use windows::Win32::Networking::WinSock::AF_UNSPEC;

#[derive(Debug)]
pub struct IfInfo {
    pub family: u16,
    pub index: u32,
    pub max_reassembly_size: u32,
    pub interface_identifier: u64,
    pub metric: u32,
    pub min_router_advertisement_interval: u32,
    pub max_router_advertisement_interval: u32,
    pub advertising_enabled: bool,
    pub forwarding_enabled: bool,
    pub weak_host_send: bool,
    pub weak_host_receive: bool,
    pub use_automatic_metric: bool,
    pub connected: bool,
}
impl From<&MIB_IPINTERFACE_ROW> for IfInfo {
    fn from(value: &MIB_IPINTERFACE_ROW) -> Self {
        IfInfo {
            family: value.Family.0,
            index: value.InterfaceIndex,
            max_reassembly_size: value.MaxReassemblySize,
            interface_identifier: value.InterfaceIdentifier,
            metric: value.Metric,

            min_router_advertisement_interval: value.MinRouterAdvertisementInterval,
            max_router_advertisement_interval: value.MaxRouterAdvertisementInterval,
            advertising_enabled: value.AdvertisingEnabled.as_bool(),
            forwarding_enabled: value.ForwardingEnabled.as_bool(),
            weak_host_send: value.WeakHostSend.as_bool(),
            weak_host_receive: value.WeakHostReceive.as_bool(),
            use_automatic_metric: value.UseAutomaticMetric.as_bool(),
            connected: value.Connected.as_bool(),
        }
    }
}
pub struct Interface {
    pub luid: NET_LUID_LH,
    pub if_info: IfInfo,
}

impl Interface {
    pub fn iter() -> Result<Vec<Interface>, Error> {
        let mut tb = MIB_IPINTERFACE_TABLE::default();
        let mut tb = std::ptr::from_mut(&mut tb);
        let mut out = Vec::new();
        unsafe {
            let res = GetIpInterfaceTable(AF_UNSPEC, std::ptr::from_mut(&mut tb));
            if res.is_err() {
                return Err(res.into());
            }
            let entries =
                slice::from_raw_parts(std::ptr::from_ref(&(*tb).Table), (*tb).NumEntries as usize);
            for entry in entries {
                let luid = entry[0].InterfaceLuid;
                let entry: IfInfo = (&entry[0]).into();
                out.push(Interface {
                    if_info: entry,
                    luid,
                })
            }
        }
        unsafe {
            FreeMibTable(tb as *const c_void);
        }
        Ok(out)
    }

    pub fn get_interface_timestamp_capabilities(&self) {
        let mut caps = INTERFACE_TIMESTAMP_CAPABILITIES::default();
        unsafe {
            let iface = std::ptr::from_ref(&self.luid);
            GetInterfaceActiveTimestampCapabilities(iface, std::ptr::from_mut(&mut caps));
        }
    }
}

#[cfg(test)]
mod test {
    use crate::error::Error;
    use crate::net_if::Interface;

    #[test]
    pub fn test() -> Result<(), Error> {
        let out = Interface::iter()?;
        for iface in &out {
            iface.get_interface_timestamp_capabilities();
        }
        Ok(())
    }
}