Skip to content

Instantly share code, notes, and snippets.

@simmsb
Created January 13, 2023 03:55
Show Gist options
  • Save simmsb/bb9fd5aaf13061cd6e4f0510eafb668e to your computer and use it in GitHub Desktop.
Save simmsb/bb9fd5aaf13061cd6e4f0510eafb668e to your computer and use it in GitHub Desktop.
use std::io::Write;
use std::net::Ipv6Addr;
use std::path::PathBuf;
use clap::Parser;
use image::{AnimationDecoder, Frame, GenericImageView, Pixel, Rgb};
use massping::packet::EchoRequestPacket;
use socket2::Domain;
#[derive(clap::Parser)]
struct Cli {
/// The destination ip prefix
dest: Ipv6Addr,
/// The image to use
image: PathBuf,
}
#[tokio::main]
async fn main() {
let Cli { dest, image } = Cli::parse();
let (tx, rx) = kanal::bounded_async(512);
let tx = tx.clone_sync();
let file_in = std::fs::File::open(image).unwrap();
let img = image::codecs::gif::GifDecoder::new(file_in).unwrap();
let frames = img.into_frames().collect_frames().unwrap();
let sender_thread = std::thread::spawn(move || sender_thread(frames, tx));
let msg = "Complain to simmsb#6785 if this is too fast :)".as_bytes();
let handles = (0..2)
.map(|_| {
let rx = rx.clone();
tokio::spawn(async move { worker(rx, dest, msg).await })
})
.collect::<Vec<_>>();
println!("Started {} workers", handles.len());
for handle in handles {
handle.await.unwrap();
}
sender_thread.join().unwrap();
}
#[derive(Debug)]
struct DrawCommand {
x: u16,
y: u16,
r: u8,
g: u8,
b: u8,
}
fn sender_thread(frames: Vec<Frame>, tx: kanal::Sender<DrawCommand>) {
loop {
for frame in &frames {
for (x, y, pix) in frame.buffer().enumerate_pixels() {
if pix.to_rgba().0[3] == 0 {
continue;
}
let Rgb([r, g, b]) = pix.to_rgb();
let cmd = DrawCommand {
x: x as u16,
y: y as u16,
r,
g,
b,
};
tx.send(cmd).unwrap();
}
std::thread::sleep(frame.delay().into());
}
}
}
impl DrawCommand {
fn format_as_ipv6(&self, prefix: Ipv6Addr) -> Ipv6Addr {
let [a, b, c, d, ..] = prefix.segments();
let d = d | self.x;
let e = self.y;
let f = self.r as u16;
let g = self.g as u16;
let h = self.b as u16;
Ipv6Addr::new(a, b, c, d, e, f, g, h)
}
}
async fn worker(rx: kanal::AsyncReceiver<DrawCommand>, prefix: Ipv6Addr, msg: &[u8]) {
let socket = match massping::raw_pinger::RawPinger::new() {
Ok(socket) => socket,
Err(e) => {
println!("Worker start fail: {:?}", e);
return;
}
};
println!("Worker starting up");
let pkt = EchoRequestPacket::new(0, 0, msg);
while let Ok(cmd) = rx.recv().await {
let dest = cmd.format_as_ipv6(prefix);
if let Err(e) = socket.send_to(dest, &pkt).await {
if e.raw_os_error() == Some(105) {
continue;
}
println!("send err ({}): {:?}\n{:?}", dest, e, cmd);
};
}
println!("worker quitting");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment