lookaround/src/main.rs

167 lines
3.8 KiB
Rust
Raw Normal View History

use std::{
2021-12-05 20:15:01 +00:00
collections::HashMap,
env,
net::{
Ipv4Addr,
2021-12-05 19:58:18 +00:00
SocketAddr,
SocketAddrV4,
UdpSocket,
},
2021-12-05 20:15:01 +00:00
time::{Duration, Instant},
};
2021-12-05 20:15:01 +00:00
use mac_address::{
MacAddress,
get_mac_address,
};
use thiserror::Error;
2021-12-05 19:58:18 +00:00
mod message;
2021-12-05 05:01:25 +00:00
mod tlv;
2021-12-05 19:58:18 +00:00
use message::{
PACKET_SIZE,
Message,
};
#[derive (Debug, Error)]
enum AppError {
#[error (transparent)]
CliArgs (#[from] CliArgError),
2021-12-05 19:58:18 +00:00
#[error (transparent)]
Io (#[from] std::io::Error),
#[error (transparent)]
MacAddr (#[from] mac_address::MacAddressError),
#[error (transparent)]
Message (#[from] message::MessageError),
#[error (transparent)]
Tlv (#[from] tlv::TlvError),
}
#[derive (Debug, Error)]
enum CliArgError {
#[error ("First argument should be a subcommand")]
MissingSubcommand,
#[error ("Unknown subcommand `{0}`")]
UnknownSubcommand (String),
}
struct CommonParams {
// Servers bind on this port, clients must send to the port
server_port: u16,
// Clients and servers will all join the same multicast addr
multicast_addr: Ipv4Addr,
}
impl Default for CommonParams {
fn default () -> Self {
Self {
server_port: 9040,
multicast_addr: Ipv4Addr::new (225, 100, 99, 98),
}
}
}
fn main () -> Result <(), AppError> {
let mut args = env::args ();
let _exe_name = args.next ();
2021-12-05 03:46:56 +00:00
match get_mac_address() {
Ok(Some(ma)) => {
2021-12-05 20:15:01 +00:00
println!("Our MAC addr = {}", ma);
2021-12-05 03:46:56 +00:00
}
Ok(None) => println!("No MAC address found."),
Err(e) => println!("{:?}", e),
}
match args.next ().as_ref ().map (|s| &s[..]) {
2021-12-05 19:58:18 +00:00
None => return Err (CliArgError::MissingSubcommand.into ()),
Some ("client") => client ()?,
Some ("server") => server ()?,
2021-12-05 19:58:18 +00:00
Some (x) => return Err (CliArgError::UnknownSubcommand (x.to_string ()).into ()),
}
Ok (())
}
fn client () -> Result <(), AppError> {
let params = CommonParams::default ();
2021-12-05 20:15:01 +00:00
let socket = UdpSocket::bind ("0.0.0.0:0")?;
2021-12-05 20:15:01 +00:00
socket.join_multicast_v4 (&params.multicast_addr, &([0u8, 0, 0, 0].into ()))?;
socket.set_read_timeout (Some (Duration::from_millis (1_000)))?;
2021-12-05 19:58:18 +00:00
let msg = Message::Request (None).to_vec ()?;
2021-12-05 20:15:01 +00:00
socket.send_to (&msg, (params.multicast_addr, params.server_port))?;
let start_time = Instant::now ();
let mut peers = HashMap::with_capacity (10);
while Instant::now () < start_time + Duration::from_secs (2) {
let (resp, remote_addr) = match recv_msg_from (&socket) {
Err (_) => continue,
Ok (x) => x,
};
let peer_mac_addr = match resp {
Message::Response (mac) => mac,
_ => continue,
};
peers.insert (peer_mac_addr, remote_addr);
}
2021-12-05 19:58:18 +00:00
2021-12-05 20:15:01 +00:00
let mut peers: Vec <_> = peers.into_iter ().collect ();
peers.sort ();
2021-12-05 20:15:01 +00:00
println! ("Found {} peers:", peers.len ());
for (mac, ip) in &peers {
match mac {
Some (mac) => println! ("{} = {}", MacAddress::new (*mac), ip),
None => println! ("<Unknown> = {}", ip),
}
}
Ok (())
}
fn server () -> Result <(), AppError> {
2021-12-05 19:58:18 +00:00
let our_mac = get_mac_address ()?.map (|x| x.bytes ());
if our_mac.is_none () {
println! ("Warning: Can't find our own MAC address. We won't be able to respond to MAC-specific lookaround requests");
}
let params = CommonParams::default ();
let socket = UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, params.server_port)).unwrap ();
socket.join_multicast_v4 (&params.multicast_addr, &([0u8, 0, 0, 0].into ())).unwrap ();
2021-12-05 20:15:01 +00:00
loop {
let (req, remote_addr) = recv_msg_from (&socket)?;
let resp = match req {
Message::Request (None) => {
Some (Message::Response (our_mac))
},
_ => continue,
};
if let Some (resp) = resp {
socket.send_to (&resp.to_vec ()?, remote_addr).unwrap ();
}
2021-12-05 19:58:18 +00:00
}
}
2021-12-05 19:58:18 +00:00
fn recv_msg_from (socket: &UdpSocket) -> Result <(Message, SocketAddr), AppError>
{
let mut buf = vec! [0u8; PACKET_SIZE];
let (bytes_recved, remote_addr) = socket.recv_from (&mut buf)?;
buf.truncate (bytes_recved);
let msg = Message::from_slice (&buf)?;
Ok ((msg, remote_addr))
}