Skip to content

Instantly share code, notes, and snippets.

@aniline
Last active December 7, 2017 10:30
Show Gist options
  • Save aniline/ebddc516ee198fd1fc3c58b6668f598d to your computer and use it in GitHub Desktop.
Save aniline/ebddc516ee198fd1fc3c58b6668f598d to your computer and use it in GitHub Desktop.
Multicast 'cat'
//
// mc_cat <mc group> <port> [<from addr>] | consumer
//
use std::env;
use std::net::{UdpSocket, SocketAddrV4, IpAddr, Ipv4Addr};
use std::str::FromStr;
use std::error::Error;
use std::io::Write;
macro_rules! eprintln(($($arg:tt)*) => { writeln!(&mut std::io::stderr(), $($arg)*).expect("Fail at failing."); } );
fn getaddr() -> Option<(Ipv4Addr, u16, Option<Ipv4Addr>)> {
let mut args = env::args();
let exe = args.next().unwrap();
match args.len() {
2...3 => {
let addr = Ipv4Addr::from_str(&args.next().unwrap());
let port = u16::from_str(&args.next().unwrap());
if port.is_ok() && addr.is_ok() {
let addr_or_gtfo = |e: String| {
Ipv4Addr::from_str(&e).map_err(|x| { eprintln!("Bad Recv From address, ignoring."); x }).ok()
};
return Some((addr.unwrap(), port.unwrap(), args.next().map_or(None, addr_or_gtfo)))
}
eprintln!("Bad MulticastV4 group or port spec.");
},
_ => {},
}
eprintln!("Usage: {} <mc_group>[:]<port>", exe);
None
}
fn do_mc_recv(mc_grp: &Ipv4Addr, port: u16, fa: &Option<Ipv4Addr>)
{
#![allow(non_snake_case)]
let INADDR_ANY = Ipv4Addr::new(0,0,0,0);
let bind_addr: SocketAddrV4 = SocketAddrV4::new(INADDR_ANY, port);
let socket: UdpSocket = match UdpSocket::bind(bind_addr) {
Ok(socket) => socket,
Err(error) => {
eprintln!("Error (Bind): {}", &error.description());
return
}
};
match socket.join_multicast_v4(&mc_grp, &INADDR_ANY) {
Err(e) => eprintln!("Error join multicast: {}", &e.description()),
Ok(()) => { },
}
let mut buf = [0u8; 65536];
match *fa {
Some(faddr) => {
let from_addr = IpAddr::V4(faddr);
loop {
match socket.recv_from(&mut buf) {
Ok((n, saddr)) => {
if from_addr == saddr.ip() {
if (&mut std::io::stdout())
.write(&buf[0..n])
.is_err() {
return
}
}
},
Err(err) => eprintln!("Err recv_from: {}", err),
}
}
}
None => {
loop {
match socket.recv_from(&mut buf) {
Ok((n, _)) => if (&mut std::io::stdout()).write(&buf[0..n]).is_err() {
return
},
Err(err) => eprintln!("Err recv_from: {}", err),
}
}
}
}
}
fn main() {
let param = getaddr();
match param {
Some((mc, port, fa)) => do_mc_recv(&mc, port, &fa),
None => ()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment