fs-share-utils 1.0.1

Core utilities for fs-share: broadcasting, networking, and file transfer primitives.
Documentation
use std::ffi::CStr;
use std::io;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

use libc::ifaddrs;

pub struct IterIpAddr {
    head: *mut ifaddrs,
    curr: *mut ifaddrs,
}

unsafe impl Send for IterIpAddr {}

impl Drop for IterIpAddr {
    fn drop(&mut self) {
        if !self.head.is_null() {
            unsafe {
                libc::freeifaddrs(self.head);
            }
        }
    }
}

impl IterIpAddr {
    pub fn new() -> io::Result<Self> {
        let mut ifaddr: *mut ifaddrs = std::ptr::null_mut();
        unsafe {
            if libc::getifaddrs(&mut ifaddr) == -1 {
                Err(io::Error::last_os_error())
            } else {
                Ok(Self {
                    head: ifaddr,
                    curr: ifaddr,
                })
            }
        }
    }
    pub fn get_addr<U: AsRef<str>, T: AsRef<[U]>>(self, ifa_name: T) -> Option<IpAddr> {
        self.filter(|(i, _)| {
            ifa_name
                .as_ref()
                .iter()
                .find(|&a| a.as_ref() == i)
                .is_some()
        })
        .next()
        .map(|(_, v)| v)
    }
    pub fn iter_ipv4(self) -> impl Iterator<Item = (String, Ipv4Addr)> {
        self.filter_map(|(a, b)| match b {
            IpAddr::V4(addr) => Some((a, addr)),
            IpAddr::V6(_) => None,
        })
    }
    pub fn iter_ipv6(self) -> impl Iterator<Item = (String, Ipv6Addr)> {
        self.filter_map(|(a, b)| match b {
            IpAddr::V4(_) => None,
            IpAddr::V6(addr) => Some((a, addr)),
        })
    }
}

impl Iterator for IterIpAddr {
    type Item = (String, IpAddr);
    fn next(&mut self) -> Option<Self::Item> {
        if self.curr.is_null() {
            return None;
        }
        unsafe {
            while !self.curr.is_null() {
                let ifa = &*self.curr;
                self.curr = ifa.ifa_next;

                if ifa.ifa_addr.is_null() {
                    continue;
                }

                let name = CStr::from_ptr(ifa.ifa_name).to_string_lossy().into_owned();
                let family = (*ifa.ifa_addr).sa_family as i32;

                match family {
                    libc::AF_INET => {
                        let sa = ifa.ifa_addr as *const libc::sockaddr_in;
                        let ip = Ipv4Addr::from(u32::from_be((*sa).sin_addr.s_addr));
                        return Some((name, IpAddr::V4(ip)));
                    }
                    libc::AF_INET6 => {
                        let sa6 = ifa.ifa_addr as *const libc::sockaddr_in6;
                        let ip = Ipv6Addr::from((*sa6).sin6_addr.s6_addr);
                        return Some((name, IpAddr::V6(ip)));
                    }
                    _ => continue,
                }
            }
        }
        None
    }
}