massping 0.5.2

ICMP ping library for sending batches of ICMP echo request packets and measuring the roundtrip time
Documentation
use std::{
    io,
    mem::MaybeUninit,
    net::SocketAddr,
    os::unix::io::{AsRawFd, RawFd},
};

use socket2::{Domain, Protocol, SockAddr, Type};

use crate::IpVersion;

pub(crate) struct BaseSocket {
    socket: socket2::Socket,
}

impl BaseSocket {
    pub(crate) fn new_icmp<V: IpVersion>() -> io::Result<Self> {
        let socket = if V::IS_V4 {
            Self::new_icmpv4()
        } else {
            Self::new_icmpv6()
        }?;

        // Required for use with tokio's AsyncFd
        socket.set_nonblocking(true)?;

        Ok(Self { socket })
    }

    fn new_icmpv4() -> io::Result<socket2::Socket> {
        socket2::Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::ICMPV4))
    }

    fn new_icmpv6() -> io::Result<socket2::Socket> {
        socket2::Socket::new(Domain::IPV6, Type::DGRAM, Some(Protocol::ICMPV6))
    }

    pub(crate) fn recv(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(usize, SocketAddr)> {
        self.socket.recv_from(buf).map(|(filled, source)| {
            (
                filled,
                source.as_socket().expect("SockAddr is an IP socket"),
            )
        })
    }

    pub(crate) fn send_to(&self, buf: &[u8], addr: SocketAddr) -> io::Result<usize> {
        let addr = SockAddr::from(addr);

        self.socket.send_to(buf, &addr)
    }
}

impl AsRawFd for BaseSocket {
    fn as_raw_fd(&self) -> RawFd {
        self.socket.as_raw_fd()
    }
}