socket-pktinfo 0.4.1

Small library to allow cross-platform handling of IP_PKTINFO and IPV6_PKTINFO with socket2 crate
Documentation
use network_interface::{NetworkInterface, NetworkInterfaceConfig};
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
use socket_pktinfo::PktInfoUdpSocket;
use std::io;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};

#[test]
fn ipv4_test() -> io::Result<()> {
    let mut interfaces = NetworkInterface::show().unwrap();
    interfaces.sort_by(|a, b| a.index.cmp(&b.index));

    let interface = interfaces
        .into_iter()
        .find(|n| {
            !n.addr.iter().any(|a| a.ip().is_loopback()) && n.addr.iter().any(|a| a.ip().is_ipv4())
        })
        .expect("Can't run test without any IPv4 network interfaces");

    let local_ip = match interface
        .addr
        .iter()
        .find(|a| a.ip().is_ipv4())
        .unwrap()
        .ip()
    {
        IpAddr::V4(ip) => ip,
        IpAddr::V6(_) => unreachable!(),
    };

    println!(
        "Testing using network interface index {}, ip {}",
        interface.index, local_ip
    );

    let port = 8000;
    let multicast_addr = Ipv4Addr::new(238, 10, 20, 31);
    let local_addr: SockAddr = SocketAddr::new(IpAddr::V4(local_ip), port).into();
    let broadcast_socket_addr: SockAddr = SocketAddr::new(Ipv4Addr::BROADCAST.into(), port).into();
    let multicast_socket_addr: SockAddr = SocketAddr::new(multicast_addr.into(), port).into();

    let mut buf = [0; 1024];
    let socket = PktInfoUdpSocket::new(Domain::IPV4)?;
    socket.set_reuse_address(true)?;
    socket.set_multicast_if_v4(&local_ip)?;
    socket.join_multicast_v4(&multicast_addr, &local_ip)?;
    socket.set_multicast_loop_v4(true)?;
    socket.set_multicast_ttl_v4(255)?;
    socket.bind(&SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port).into())?;

    let std_udp_socket = socket.try_clone_std()?;
    assert!(
        std_udp_socket.local_addr()? == SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port)
    );

    {
        let output_socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?;
        let data = "Hello";
        output_socket.send_to(data.as_bytes(), &local_addr)?;
    }

    let (_, info) = socket.recv(&mut buf)?;
    println!(
        "Unicast packet received on interface index {} from src {} with destination ip {}",
        info.if_index, info.addr_src, info.addr_dst,
    );

    {
        let output_socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?;
        output_socket.set_broadcast(true)?;
        let data = "Hello";
        output_socket.send_to(data.as_bytes(), &broadcast_socket_addr)?;
    }

    let (_, info) = socket.recv(&mut buf)?;
    println!(
        "Broadcast packet received on interface index {} from src {} with destination ip {}",
        info.if_index, info.addr_src, info.addr_dst,
    );

    {
        let output_socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?;
        output_socket.set_multicast_if_v4(&local_ip)?;
        output_socket.set_multicast_loop_v4(true)?;
        let data = "Hello";
        output_socket.send_to(data.as_bytes(), &multicast_socket_addr)?;
    }

    let (_, info) = socket.recv(&mut buf)?;
    println!(
        "Multicast packet received on interface index {} from src {} with destination ip {}",
        info.if_index, info.addr_src, info.addr_dst,
    );

    Ok(())
}