2021-11-26 21:46:27 +00:00
|
|
|
use std::{
|
2021-12-05 20:15:01 +00:00
|
|
|
collections::HashMap,
|
2021-11-26 21:46:27 +00:00
|
|
|
env,
|
|
|
|
net::{
|
|
|
|
Ipv4Addr,
|
2021-12-05 19:58:18 +00:00
|
|
|
SocketAddr,
|
2021-12-05 03:39:53 +00:00
|
|
|
SocketAddrV4,
|
2021-11-26 21:46:27 +00:00
|
|
|
UdpSocket,
|
|
|
|
},
|
2021-12-05 20:15:01 +00:00
|
|
|
time::{Duration, Instant},
|
2021-11-26 21:46:27 +00:00
|
|
|
};
|
|
|
|
|
2021-12-05 20:15:01 +00:00
|
|
|
use mac_address::{
|
|
|
|
MacAddress,
|
|
|
|
get_mac_address,
|
|
|
|
};
|
2021-12-05 03:39:53 +00:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2021-12-05 03:39:53 +00:00
|
|
|
#[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),
|
2021-12-05 03:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-26 21:46:27 +00:00
|
|
|
|
2021-12-05 03:39:53 +00:00
|
|
|
fn main () -> Result <(), AppError> {
|
2021-11-26 21:46:27 +00:00
|
|
|
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),
|
|
|
|
}
|
|
|
|
|
2021-11-26 21:46:27 +00:00
|
|
|
match args.next ().as_ref ().map (|s| &s[..]) {
|
2021-12-05 19:58:18 +00:00
|
|
|
None => return Err (CliArgError::MissingSubcommand.into ()),
|
2021-11-26 21:46:27 +00:00
|
|
|
Some ("client") => client ()?,
|
|
|
|
Some ("server") => server ()?,
|
2021-12-05 19:58:18 +00:00
|
|
|
Some (x) => return Err (CliArgError::UnknownSubcommand (x.to_string ()).into ()),
|
2021-11-26 21:46:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok (())
|
|
|
|
}
|
|
|
|
|
2021-12-05 03:39:53 +00:00
|
|
|
fn client () -> Result <(), AppError> {
|
2021-12-05 20:40:37 +00:00
|
|
|
use rand::RngCore;
|
|
|
|
|
2021-12-05 03:39:53 +00:00
|
|
|
let params = CommonParams::default ();
|
2021-12-05 20:15:01 +00:00
|
|
|
let socket = UdpSocket::bind ("0.0.0.0:0")?;
|
2021-11-26 21:46:27 +00:00
|
|
|
|
2021-12-05 20:15:01 +00:00
|
|
|
socket.join_multicast_v4 (¶ms.multicast_addr, &([0u8, 0, 0, 0].into ()))?;
|
|
|
|
socket.set_read_timeout (Some (Duration::from_millis (1_000)))?;
|
2021-11-26 21:46:27 +00:00
|
|
|
|
2021-12-05 20:40:37 +00:00
|
|
|
let mut idem_id = [0u8; 8];
|
|
|
|
rand::thread_rng ().fill_bytes (&mut idem_id);
|
|
|
|
|
|
|
|
let msg = Message::Request {
|
|
|
|
idem_id,
|
|
|
|
mac: None,
|
|
|
|
}.to_vec ()?;
|
|
|
|
|
2021-12-05 20:42:56 +00:00
|
|
|
for _ in 0..10 {
|
2021-12-05 20:40:37 +00:00
|
|
|
socket.send_to (&msg, (params.multicast_addr, params.server_port))?;
|
2021-12-05 20:42:56 +00:00
|
|
|
std::thread::sleep (Duration::from_millis (100));
|
2021-12-05 20:40:37 +00:00
|
|
|
}
|
2021-12-05 20:15:01 +00:00
|
|
|
|
|
|
|
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-11-26 21:46:27 +00:00
|
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|
2021-12-05 03:43:12 +00:00
|
|
|
|
2021-11-26 21:46:27 +00:00
|
|
|
Ok (())
|
|
|
|
}
|
|
|
|
|
2021-12-05 03:39:53 +00:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2021-12-05 03:39:53 +00:00
|
|
|
let params = CommonParams::default ();
|
|
|
|
let socket = UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, params.server_port)).unwrap ();
|
2021-11-26 21:46:27 +00:00
|
|
|
|
2021-12-05 20:22:12 +00:00
|
|
|
socket.join_multicast_v4 (¶ms.multicast_addr, &([0u8, 0, 0, 0].into ())).unwrap ();
|
|
|
|
|
2021-12-05 20:40:37 +00:00
|
|
|
let mut recent_idem_ids = Vec::with_capacity (32);
|
|
|
|
|
2021-12-05 20:15:01 +00:00
|
|
|
loop {
|
2021-12-05 20:16:47 +00:00
|
|
|
println! ("Waiting for messages...");
|
2021-12-05 20:15:01 +00:00
|
|
|
let (req, remote_addr) = recv_msg_from (&socket)?;
|
|
|
|
|
|
|
|
let resp = match req {
|
2021-12-05 20:40:37 +00:00
|
|
|
Message::Request {
|
|
|
|
mac: None,
|
|
|
|
idem_id,
|
|
|
|
} => {
|
|
|
|
if recent_idem_ids.contains (&idem_id) {
|
|
|
|
println! ("Ignoring request we already processed");
|
|
|
|
None
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
recent_idem_ids.insert (0, idem_id);
|
|
|
|
recent_idem_ids.truncate (30);
|
|
|
|
Some (Message::Response (our_mac))
|
|
|
|
}
|
2021-12-05 20:15:01 +00:00
|
|
|
},
|
|
|
|
_ => continue,
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some (resp) = resp {
|
|
|
|
socket.send_to (&resp.to_vec ()?, remote_addr).unwrap ();
|
|
|
|
}
|
2021-12-05 19:58:18 +00:00
|
|
|
}
|
2021-11-26 21:46:27 +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))
|
|
|
|
}
|