mcrx-core 0.3.0

Runtime-agnostic and portable multicast receiver library for IPv4 and IPv6 ASM/SSM.
Documentation
use mcrx_core::{RawSubscriptionConfig, SharedRawContext};
use std::env;
use std::error::Error;
use std::net::IpAddr;
use std::thread;
use std::time::Duration;

fn main() -> Result<(), Box<dyn Error>> {
    let mut args = env::args().skip(1);
    let Some(group) = args.next() else {
        print_usage();
        return Ok(());
    };
    let Some(interface) = args.next() else {
        print_usage();
        return Ok(());
    };
    let source = args.next();
    if args.next().is_some() {
        print_usage();
        return Ok(());
    }

    let group: IpAddr = group.parse()?;
    let interface: IpAddr = interface.parse()?;
    let source_address = source.as_deref().map(str::parse).transpose()?;
    let mut config = match source_address {
        Some(source) => RawSubscriptionConfig::ssm_ip(group, source),
        None => RawSubscriptionConfig::asm_ip(group),
    };
    config.interface = Some(interface);

    let mut context = SharedRawContext::new();
    let id = context.add_subscription(config)?;
    context.join_subscription(id)?;

    println!("shared raw capture ready");
    println!("  group:      {group}");
    println!("  interface:  {interface}");
    println!("  source:     {}", source.as_deref().unwrap_or("any"));
    println!("  sub_id:     {}", id.0);

    loop {
        if let Some(packet) = context.try_recv_any()? {
            println!(
                "received {} raw bytes matching {:?}",
                packet.packet.datagram_len(),
                packet.matching_subscription_ids()
            );
        } else {
            thread::sleep(Duration::from_millis(10));
        }
    }
}

fn print_usage() {
    eprintln!("usage: shared_raw_capture <group> <interface> [source]");
    eprintln!("example: shared_raw_capture 239.1.2.3 192.168.1.20");
    eprintln!("example: shared_raw_capture 232.1.2.3 192.168.1.20 192.168.1.10");
}