use std::{
net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket},
slice::ChunksExact,
time::Duration,
};
pub fn checksum(data: &[u8]) -> u16 {
let mut sum = 0xBEAFu32;
for &d in data {
sum += u32::from(d);
}
return sum as u16;
}
pub fn compute_generic_checksum(buf: &[u8]) -> u16 {
let mut state: u32 = 0xFFFF;
let mut chunks_iter: ChunksExact<u8> = buf.chunks_exact(2);
while let Some(chunk) = chunks_iter.next() {
state += u16::from_le_bytes([chunk[0], chunk[1]]) as u32;
}
if let Some(&b) = chunks_iter.remainder().get(0) {
state += u16::from_le_bytes([b, 0]) as u32;
}
state = (state >> 16) + (state & 0xffff);
state = !state & 0xffff;
state as u16
}
pub fn local_ip_or(ip: Option<Ipv4Addr>) -> Result<IpAddr, String> {
Ok(match ip {
Some(ip) => IpAddr::V4(ip),
None => get_if_addrs::get_if_addrs()
.map_err(|e| {
format!(
"Could not automatically determine machine IP address. {}",
e
)
})?
.iter()
.find(|x| x.ip().is_ipv4() && !x.ip().is_loopback())
.ok_or("Could not find a local IPv4 address!")?
.ip(),
})
}
fn send_and_receive_impl(
msg: &[u8],
addr: Ipv4Addr,
port: Option<u16>,
) -> Result<UdpSocket, String> {
let unspecified_addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, port.unwrap_or(0)));
let destination_addr = SocketAddr::from((addr, 80));
let socket = UdpSocket::bind(unspecified_addr)
.map_err(|e| format!("Could not bind to any port. {}", e))?;
socket
.set_broadcast(true)
.map_err(|e| format!("Could not enable broadcast. {}", e))?;
socket
.set_read_timeout(Some(Duration::new(10, 0)))
.map_err(|e| format!("Could not set read timeout! {}", e))?;
socket
.send_to(&msg, destination_addr)
.map_err(|e| format!("Could not broadcast message! {}", e))?;
return Ok(socket);
}
pub fn send_and_receive_many<I, T>(
msg: &[u8],
addr: Ipv4Addr,
port: Option<u16>,
cb: T,
) -> Result<Vec<I>, String>
where
T: Fn(usize, &[u8], SocketAddr) -> Result<I, String>,
{
let socket = send_and_receive_impl(msg, addr, port)
.map_err(|e| format!("Could not create socket for message sending! {}", e))?;
let mut results: Vec<I> = vec![];
let mut recv_buffer = [0u8; 8092];
while let Ok((bytes_received, addr)) = socket.recv_from(&mut recv_buffer) {
results.push(cb(bytes_received, &recv_buffer[0..bytes_received], addr)?);
}
return Ok(results);
}
pub fn send_and_receive_one<I, T>(
msg: &[u8],
addr: Ipv4Addr,
port: Option<u16>,
cb: T,
) -> Result<I, String>
where
T: Fn(usize, &[u8], SocketAddr) -> Result<I, String>,
{
let socket = send_and_receive_impl(msg, addr, port)
.map_err(|e| format!("Could not create socket for message sending! {}", e))?;
let mut recv_buffer = [0u8; 8092];
if let Ok((bytes_received, addr)) = socket.recv_from(&mut recv_buffer) {
return Ok(cb(bytes_received, &recv_buffer[0..bytes_received], addr)?);
}
return Err("No response within timeout!".into());
}
pub fn reverse_mac(mac_flipped: [u8; 6]) -> [u8; 6] {
let mut mac = [0u8; 6];
for i in 0..6 {
mac[i] = mac_flipped[6 - i - 1];
}
return mac;
}